import asyncio
import json
import re
import time
import base64
import os
from loguru import logger
import websockets
from utils.xianyu_utils import (
    decrypt, generate_mid, generate_uuid, trans_cookies,
    generate_device_id, generate_sign
)
from config import (
    WEBSOCKET_URL, HEARTBEAT_INTERVAL, HEARTBEAT_TIMEOUT,
    config, COOKIES_STR, LOG_CONFIG, AUTO_REPLY, DEFAULT_HEADERS,
    WEBSOCKET_HEADERS, APP_CONFIG, API_ENDPOINTS
)

import sys
import aiohttp

# JH API现在使用签名验证方式，不再需要token管理器

class AutoReplyPauseManager:
    """自动回复暂停管理器"""
    def __init__(self):
        # 存储每个chat_id的暂停信息 {chat_id: pause_until_timestamp}
        self.paused_chats = {}
        # 存储永久暂停的chat_id集合（转人工后的会话）
        self.permanently_paused_chats = set()
        # 从数据库加载永久暂停的会话
        self._load_permanently_paused_chats()

    def _load_permanently_paused_chats(self):
        """从数据库加载永久暂停的会话"""
        try:
            from db_manager import db_manager
            permanently_paused = db_manager.get_permanently_paused_chats()
            self.permanently_paused_chats = set(permanently_paused)
            logger.info(f"从数据库加载了 {len(self.permanently_paused_chats)} 个永久暂停的会话")
        except Exception as e:
            logger.error(f"加载永久暂停会话失败: {self._safe_str(e)}")

    def pause_chat(self, chat_id: str, cookie_id: str):
        """暂停指定chat_id的自动回复，使用账号特定的暂停时间"""
        # 先检查账号是否启用了暂停功能
        try:
            from db_manager import db_manager
            pause_enabled = db_manager.get_pause_enabled(cookie_id)
            if not pause_enabled:
                logger.info(f"【{cookie_id}】检测到手动发出消息，但该账号的暂停功能已禁用，不执行暂停逻辑")
                return
        except Exception as e:
            logger.error(f"检查账号 {cookie_id} 暂停功能开关失败: {self._safe_str(e)}，默认启用暂停功能")
            
        # 获取账号特定的暂停时间
        try:
            from db_manager import db_manager
            pause_minutes = db_manager.get_cookie_pause_duration(cookie_id)
        except Exception as e:
            logger.error(f"获取账号 {cookie_id} 暂停时间失败: {self._safe_str(e)}，使用默认10分钟")
            pause_minutes = 10

        pause_duration_seconds = pause_minutes * 60
        pause_until = time.time() + pause_duration_seconds
        self.paused_chats[chat_id] = pause_until

        # 计算暂停结束时间
        end_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(pause_until))
        logger.info(f"【{cookie_id}】检测到手动发出消息，chat_id {chat_id} 自动回复暂停{pause_minutes}分钟，恢复时间: {end_time}")

    def pause_chat_permanently(self, chat_id: str, cookie_id: str, reason: str = "转人工"):
        """永久暂停指定chat_id的自动回复（用于转人工等场景）"""
        try:
            # 添加到永久暂停集合
            self.permanently_paused_chats.add(chat_id)
            
            # 保存到数据库
            from db_manager import db_manager
            db_manager.add_permanently_paused_chat(chat_id, cookie_id, reason)
            
            logger.info(f"【{cookie_id}】chat_id {chat_id} 已永久暂停自动回复，原因: {reason}")
        except Exception as e:
            logger.error(f"永久暂停chat_id {chat_id}失败: {e}")

    def resume_permanently_paused_chat(self, chat_id: str, cookie_id: str):
        """恢复永久暂停的会话（管理员手动操作）"""
        try:
            # 从永久暂停集合移除
            self.permanently_paused_chats.discard(chat_id)
            
            # 从数据库移除
            from db_manager import db_manager
            db_manager.remove_permanently_paused_chat(chat_id)
            
            logger.info(f"【{cookie_id}】chat_id {chat_id} 已恢复自动回复")
            return True
        except Exception as e:
            logger.error(f"恢复永久暂停的chat_id {chat_id}失败: {e}")
            return False

    def is_chat_paused(self, chat_id: str) -> bool:
        """检查指定chat_id是否处于暂停状态"""
        # 首先检查是否永久暂停
        if chat_id in self.permanently_paused_chats:
            return True
            
        # 再检查临时暂停
        if chat_id not in self.paused_chats:
            return False

        current_time = time.time()
        pause_until = self.paused_chats[chat_id]

        if current_time >= pause_until:
            # 暂停时间已过，移除记录
            del self.paused_chats[chat_id]
            return False

        return True

    def get_remaining_pause_time(self, chat_id: str) -> int:
        """获取指定chat_id剩余暂停时间（秒）"""
        # 永久暂停返回-1表示无限期
        if chat_id in self.permanently_paused_chats:
            return -1
            
        if chat_id not in self.paused_chats:
            return 0

        current_time = time.time()
        pause_until = self.paused_chats[chat_id]
        remaining = max(0, int(pause_until - current_time))

        return remaining

    def get_pause_status(self, chat_id: str) -> dict:
        """获取会话的详细暂停状态"""
        if chat_id in self.permanently_paused_chats:
            return {
                'paused': True,
                'type': 'permanent',
                'reason': '转人工',
                'remaining_time': -1
            }
        elif chat_id in self.paused_chats:
            remaining_time = self.get_remaining_pause_time(chat_id)
            if remaining_time > 0:
                return {
                    'paused': True,
                    'type': 'temporary',
                    'reason': '手动发送消息',
                    'remaining_time': remaining_time
                }
        
        return {
            'paused': False,
            'type': None,
            'reason': None,
            'remaining_time': 0
        }

    def cleanup_expired_pauses(self):
        """清理已过期的暂停记录"""
        current_time = time.time()
        expired_chats = [chat_id for chat_id, pause_until in self.paused_chats.items()
                        if current_time >= pause_until]

        for chat_id in expired_chats:
            del self.paused_chats[chat_id]


# 全局暂停管理器实例
pause_manager = AutoReplyPauseManager()

# 日志配置
log_dir = 'logs'
os.makedirs(log_dir, exist_ok=True)
log_path = os.path.join(log_dir, f"xianyu_{time.strftime('%Y-%m-%d')}.log")
logger.remove()
logger.add(
    log_path,
    rotation=LOG_CONFIG.get('rotation', '1 day'),
    retention=LOG_CONFIG.get('retention', '7 days'),
    compression=LOG_CONFIG.get('compression', 'zip'),
    level=LOG_CONFIG.get('level', 'INFO'),
    format=LOG_CONFIG.get('format', '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>'),
    encoding='utf-8',
    enqueue=True
)
logger.add(
    sys.stdout,
    level=LOG_CONFIG.get('level', 'INFO'),
    format=LOG_CONFIG.get('format', '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>'),
    enqueue=True
)

class XianyuLive:
    # 类级别的锁字典，为每个order_id维护一个锁（用于订单详情获取防重复）
    _order_detail_locks = {}
    _order_detail_lock = asyncio.Lock()
    
    def _safe_str(self, e):
        """安全地将异常转换为字符串，确保编码安全"""
        try:
            # 首先尝试标准转换
            result = str(e)
            # 使用安全编码处理确保结果可以用于日志输出
            return self._safe_encode_data_simple(result)
        except:
            try:
                # 尝试repr
                result = repr(e)
                return self._safe_encode_data_simple(result)
            except:
                return "未知错误"
    
    def _safe_encode_data_simple(self, data):
        """简化版的安全编码处理，避免循环调用"""
        try:
            if data is None:
                return ""
            
            # 如果是字节类型，尝试解码
            if isinstance(data, bytes):
                try:
                    return data.decode('utf-8', errors='ignore')
                except:
                    try:
                        return data.decode('gbk', errors='ignore')
                    except:
                        return data.decode('ascii', errors='ignore')
            
            # 如果已经是字符串，检查是否包含问题字符
            if isinstance(data, str):
                try:
                    # 尝试编码为UTF-8再解码，清理问题字符
                    return data.encode('utf-8', errors='ignore').decode('utf-8', errors='ignore')
                except:
                    # 如果失败，只保留ASCII字符
                    return ''.join(char for char in data if ord(char) < 128)
            
            # 其他类型转换为字符串
            return str(data)
            
        except:
            return "编码处理失败"
    
    def _safe_encode_data(self, data):
        """安全地处理数据编码，确保能正确处理特殊字符"""
        try:
            if data is None:
                return ""
            
            # 如果是字节类型，尝试解码
            if isinstance(data, bytes):
                try:
                    # 尝试UTF-8解码
                    return data.decode('utf-8', errors='ignore')
                except:
                    try:
                        # 尝试其他编码
                        return data.decode('gbk', errors='ignore')
                    except:
                        # 如果都失败，使用ASCII并忽略错误
                        return data.decode('ascii', errors='ignore')
            
            # 如果已经是字符串，检查是否包含问题字符
            if isinstance(data, str):
                try:
                    # 尝试编码为UTF-8再解码，清理问题字符
                    return data.encode('utf-8', errors='ignore').decode('utf-8', errors='ignore')
                except:
                    # 如果失败，只保留ASCII字符
                    return ''.join(char for char in data if ord(char) < 128)
            
            # 其他类型转换为字符串
            return str(data)
            
        except Exception as e:
            logger.warning(f"数据编码处理失败: {self._safe_str(e)}，使用空字符串")
            return ""

    def __init__(self, cookies_str=None, cookie_id: str = "default", user_id: int = None):
        """初始化闲鱼直播类"""
        logger.info(f"【{cookie_id}】开始初始化XianyuLive...")

        if not cookies_str:
            cookies_str = COOKIES_STR
        if not cookies_str:
            raise ValueError("未提供cookies，请在global_config.yml中配置COOKIES_STR或通过参数传入")

        logger.info(f"【{cookie_id}】解析cookies...")
        self.cookies = trans_cookies(cookies_str)
        logger.info(f"【{cookie_id}】cookies解析完成，包含字段: {list(self.cookies.keys())}")

        self.cookie_id = cookie_id  # 唯一账号标识
        self.cookies_str = cookies_str  # 保存原始cookie字符串
        self.user_id = user_id  # 保存用户ID，用于token刷新时保持正确的所有者关系
        self.base_url = WEBSOCKET_URL

        if 'unb' not in self.cookies:
            raise ValueError(f"【{cookie_id}】Cookie中缺少必需的'unb'字段，当前字段: {list(self.cookies.keys())}")

        self.myid = self.cookies['unb']
        logger.info(f"【{cookie_id}】用户ID: {self.myid}")
        self.device_id = generate_device_id(self.myid)
        
        # 心跳相关配置
        self.heartbeat_interval = HEARTBEAT_INTERVAL
        self.heartbeat_timeout = HEARTBEAT_TIMEOUT
        self.last_heartbeat_time = 0
        self.last_heartbeat_response = 0
        self.heartbeat_task = None
        self.ws = None
        
        # Token相关配置（仅用于cookie更新时的刷新）
        self.current_token = None
        self.connection_restart_flag = False  # 连接重启标志

        # 通知防重复机制
        self.last_notification_time = {}  # 记录每种通知类型的最后发送时间
        self.notification_cooldown = 300  # 5分钟内不重复发送相同类型的通知
        self.token_refresh_notification_cooldown = 86400  # Token刷新异常通知冷却时间：24小时

        # 自动发货防重复机制
        self.last_delivery_time = {}  # 记录每个商品的最后发货时间
        self.delivery_cooldown = 600  # 10分钟内不重复发货

        # 自动确认发货防重复机制
        self.confirmed_orders = {}  # 记录已确认发货的订单，防止重复确认
        self.order_confirm_cooldown = 600  # 10分钟内不重复确认同一订单

        # 订单级别的发货锁机制（防止重复触发）
        self.delivery_locks = {}  # 记录正在处理的订单发货，防止并发处理
        self.processing_orders = set()  # 正在处理的订单ID集合

        self.session = None  # 用于API调用的aiohttp session

        # 启动定期清理过期暂停记录的任务
        self.cleanup_task = None

        # 注意：已移除Cookie自动续期功能，仅保留用户主动更新cookie时的token刷新

    def is_auto_confirm_enabled(self) -> bool:
        """检查当前账号是否启用自动确认发货"""
        try:
            from db_manager import db_manager
            return db_manager.get_auto_confirm(self.cookie_id)
        except Exception as e:
            logger.error(f"【{self.cookie_id}】获取自动确认发货设置失败: {self._safe_str(e)}")
            return True  # 出错时默认启用



    def can_auto_delivery(self, order_id: str) -> bool:
        """检查是否可以进行自动发货（防重复发货）- 基于订单ID"""
        if not order_id:
            # 如果没有订单ID，则不进行冷却检查，允许发货
            return True

        # 检查是否正在处理中（防止并发）
        if order_id in self.processing_orders:
            logger.info(f"【{self.cookie_id}】订单 {order_id} 正在处理中，跳过重复发货")
            return False

        # 首先检查数据库中的订单状态（最可靠的检查）
        try:
            from db_manager import db_manager
            existing_order = db_manager.get_order_by_id(order_id, self.cookie_id)
            if existing_order and existing_order.get('order_status') == '已发货':
                logger.info(f"【{self.cookie_id}】订单 {order_id} 在数据库中已标记为已发货，跳过重复发货")
                return False
        except Exception as e:
            logger.warning(f"【{self.cookie_id}】检查订单数据库状态失败: {self._safe_str(e)}，继续时间冷却检查")

        # 检查时间冷却（内存中的备用检查）
        current_time = time.time()
        last_delivery = self.last_delivery_time.get(order_id, 0)

        if current_time - last_delivery < self.delivery_cooldown:
            logger.info(f"【{self.cookie_id}】订单 {order_id} 在冷却期内，跳过自动发货")
            return False

        # 如果数据库检查和冷却时间检查都通过，但这是"记得及时发货"消息，则通过API进一步检查
        # 这个检查只在特定情况下进行，避免过度调用API
        if hasattr(self, '_current_trigger_message') and '记得及时发货' in self._current_trigger_message:
            try:
                logger.info(f"【{self.cookie_id}】收到'记得及时发货'消息，通过API进一步检查订单状态: {order_id}")
                api_shipped = self._check_order_shipped_via_api(order_id)
                if api_shipped:
                    logger.info(f"【{self.cookie_id}】API检查显示订单 {order_id} 已发货，跳过重复发货")
                    return False
                else:
                    logger.info(f"【{self.cookie_id}】API检查显示订单 {order_id} 未发货，允许继续发货")
            except Exception as e:
                logger.warning(f"【{self.cookie_id}】API检查订单状态失败: {self._safe_str(e)}，允许继续发货")

        return True

    def _check_order_shipped_via_api(self, order_id: str) -> bool:
        """通过API检查订单是否已发货
        
        Args:
            order_id: 订单ID
            
        Returns:
            bool: True表示已发货，False表示未发货
        """
        try:
            from utils.order_detail_fetcher import OrderDetailFetcher
            
            # 创建订单详情获取器
            fetcher = OrderDetailFetcher(self.cookie_id)
            
            # 通过API获取订单详情
            api_result = fetcher.fetch_order_detail_via_api(order_id)
            
            if not api_result:
                logger.warning(f"【{self.cookie_id}】API获取订单详情失败: {order_id}")
                return False
            
            # 检查API返回的原始数据中的utArgs.orderMainTitle字段
            if 'raw_api_data' in api_result:
                raw_data = api_result['raw_api_data']
                ut_args = raw_data.get('data', {}).get('utArgs', {})
                order_main_title = ut_args.get('orderMainTitle', '')
                
                logger.info(f"【{self.cookie_id}】API返回的订单主标题: {order_main_title}")
                
                # 检查是否包含已发货的标识
                if '已发货，待买家确认收货' in order_main_title:
                    logger.info(f"【{self.cookie_id}】API检查确认订单 {order_id} 已发货")
                    return True
                else:
                    logger.info(f"【{self.cookie_id}】API检查显示订单 {order_id} 未发货，主标题: {order_main_title}")
                    return False
            else:
                logger.warning(f"【{self.cookie_id}】API返回数据中缺少raw_api_data字段")
                return False
                
        except Exception as e:
            logger.error(f"【{self.cookie_id}】API检查订单发货状态异常: {self._safe_str(e)}")
            return False
        finally:
            # 确保关闭fetcher
            try:
                if 'fetcher' in locals():
                    fetcher.close()
            except:
                pass

    def mark_delivery_sent(self, order_id: str):
        """标记订单已发货 - 基于订单ID"""
        if order_id:
            self.last_delivery_time[order_id] = time.time()
            # 从处理中集合移除
            self.processing_orders.discard(order_id)
            logger.debug(f"【{self.cookie_id}】标记订单 {order_id} 已发货")
        else:
            logger.debug(f"【{self.cookie_id}】无订单ID，跳过发货标记")

    def mark_delivery_processing(self, order_id: str):
        """标记订单正在处理发货"""
        if order_id:
            self.processing_orders.add(order_id)
            logger.debug(f"【{self.cookie_id}】标记订单 {order_id} 开始处理发货")

    def unmark_delivery_processing(self, order_id: str):
        """取消订单发货处理标记"""
        if order_id:
            self.processing_orders.discard(order_id)
            logger.debug(f"【{self.cookie_id}】取消订单 {order_id} 发货处理标记")

    def _is_auto_delivery_trigger(self, message: str) -> bool:
        """检查消息是否为自动发货触发关键字"""
        # 明确排除待付款状态的消息
        excluded_keywords = [
            '[我已拍下，待付款]',
            '我已拍下，待付款',
            '[已拍下，待付款]',
            '已拍下，待付款',
            '等待买家付款',
            '买家已拍下，待付款'
        ]
        
        # 首先检查是否包含排除的关键字
        for excluded_keyword in excluded_keywords:
            if excluded_keyword in message:
                return False
        
        # 定义所有自动发货触发关键字（仅付款成功后的状态）
        auto_delivery_keywords = [
            # 付款完成的系统消息
            '[我已付款，等待你发货]',
            '[已付款，待发货]',
            '我已付款，等待你发货',
            '[记得及时发货]',
            '等待你发货',
            '等待卖家发货'
        ]

        # 检查消息是否包含任何触发关键字
        for keyword in auto_delivery_keywords:
            if keyword in message:
                return True

        return False

    def _extract_order_id(self, message: dict) -> str:
        """从消息中提取订单ID"""
        try:
            order_id = None

            # 先查看消息的完整结构
            logger.debug(f"【{self.cookie_id}】🔍 完整消息结构: {message}")

            # 检查message['1']的结构
            message_1 = message.get('1', {})
            logger.debug(f"【{self.cookie_id}】🔍 message['1'] keys: {list(message_1.keys()) if message_1 else 'None'}")

            # 检查message['1']['6']的结构
            message_1_6 = message_1.get('6', {}) if message_1 else {}
            logger.debug(f"【{self.cookie_id}】🔍 message['1']['6'] keys: {list(message_1_6.keys()) if message_1_6 else 'None'}")

            # 方法1: 从button的targetUrl中提取orderId
            content_json_str = message.get('1', {}).get('6', {}).get('3', {}).get('5', '')
            if content_json_str:
                try:
                    content_data = json.loads(content_json_str)

                    # 方法1a: 从button的targetUrl中提取orderId
                    target_url = content_data.get('dxCard', {}).get('item', {}).get('main', {}).get('exContent', {}).get('button', {}).get('targetUrl', '')
                    if target_url:
                        # 从URL中提取orderId参数
                        order_match = re.search(r'orderId=(\d+)', target_url)
                        if order_match:
                            order_id = order_match.group(1)
                            logger.info(f'【{self.cookie_id}】✅ 从button提取到订单ID: {order_id}')

                    # 方法1b: 从main的targetUrl中提取order_detail的id
                    if not order_id:
                        main_target_url = content_data.get('dxCard', {}).get('item', {}).get('main', {}).get('targetUrl', '')
                        if main_target_url:
                            order_match = re.search(r'order_detail\?id=(\d+)', main_target_url)
                            if order_match:
                                order_id = order_match.group(1)
                                logger.info(f'【{self.cookie_id}】✅ 从main targetUrl提取到订单ID: {order_id}')

                except Exception as parse_e:
                    logger.debug(f"解析内容JSON失败: {parse_e}")

            # 方法2: 从dynamicOperation中的URL提取orderId
            if not order_id and content_json_str:
                try:
                    content_data = json.loads(content_json_str)
                    dynamic_target_url = content_data.get('dynamicOperation', {}).get('changeContent', {}).get('dxCard', {}).get('item', {}).get('main', {}).get('exContent', {}).get('button', {}).get('targetUrl', '')
                    if dynamic_target_url:
                        # 先尝试从URL中提取orderId参数
                        order_match = re.search(r'orderId=(\d+)', dynamic_target_url)
                        if order_match:
                            order_id = order_match.group(1)
                            logger.info(f'【{self.cookie_id}】✅ 从dynamicOperation提取到订单ID(orderId): {order_id}')
                        else:
                            # 再尝试从order_detail URL中提取id参数
                            order_match = re.search(r'order_detail\?id=(\d+)', dynamic_target_url)
                            if order_match:
                                order_id = order_match.group(1)
                                logger.info(f'【{self.cookie_id}】✅ 从order_detail提取到订单ID(id): {order_id}')
                except Exception as parse_e:
                    logger.debug(f"解析dynamicOperation JSON失败: {parse_e}")

            # 方法3: 从extJson的updateKey中提取订单ID（针对交易成功等状态消息）
            if not order_id and isinstance(message, dict) and "1" in message:
                message_1 = message.get("1", {})
                if isinstance(message_1, dict) and "10" in message_1:
                    message_10 = message_1.get("10", {})
                    if isinstance(message_10, dict):
                        ext_json_str = message_10.get("extJson", "{}")
                        try:
                            ext_json = json.loads(ext_json_str)
                            update_key = ext_json.get("updateKey", "")
                            if ":" in update_key:
                                parts = update_key.split(":")
                                if len(parts) >= 2:
                                    order_id = parts[1]
                                    logger.info(f'【{self.cookie_id}】✅ 从extJson updateKey提取到订单ID: {order_id}')
                        except Exception as parse_e:
                            logger.debug(f"解析extJson失败: {parse_e}")

            # 方法4: 从简化消息结构中提取（针对状态更新消息）
            if not order_id and isinstance(message, dict):
                # 检查是否为简化的状态消息格式
                # 格式如: {'1': '商品ID@goofish', '2': 1, '3': {'redReminder': '交易成功', 'redReminderStyle': '10'}, '4': timestamp}
                if '1' in message and isinstance(message['1'], str) and '@goofish' in message['1']:
                    # 从'1'字段提取商品ID
                    item_id_raw = message['1'].replace('@goofish', '')
                    logger.debug(f'【{self.cookie_id}】从简化消息提取到商品ID: {item_id_raw}')
                    
                    # 这种情况下，可能需要从数据库中查找最近的订单
                    if '3' in message and isinstance(message['3'], dict):
                        red_reminder = message['3'].get('redReminder')
                        if red_reminder in ['交易成功', '等待卖家发货', '已付款，待发货']:
                            logger.info(f'【{self.cookie_id}】检测到状态消息: {red_reminder}，尝试从数据库查找最近订单')
                            try:
                                from db_manager import db_manager
                                # 查找该商品最近的订单
                                recent_order = db_manager.get_recent_order_by_item_id(item_id_raw, self.cookie_id)
                                if recent_order:
                                    order_id = recent_order.get('order_id')
                                    logger.info(f'【{self.cookie_id}】✅ 从数据库查找到最近订单ID: {order_id}')
                            except Exception as db_e:
                                logger.debug(f"从数据库查找最近订单失败: {db_e}")

            return order_id

        except Exception as e:
            logger.error(f"提取订单ID失败: {self._safe_str(e)}")
            return None

    def _is_image_message(self, message: dict) -> bool:
        """判断是否为图片消息"""
        try:
            # 检查消息结构
            if not isinstance(message, dict) or '1' not in message:
                return False

            message_1 = message.get('1', {})
            if not isinstance(message_1, dict) or '6' not in message_1:
                return False

            message_6 = message_1.get('6', {})
            if not isinstance(message_6, dict) or '3' not in message_6:
                return False

            message_6_3 = message_6.get('3', {})
            if not isinstance(message_6_3, dict) or '5' not in message_6_3:
                return False

            # 获取消息内容
            content_str = message_6_3.get('5', '')
            if not content_str:
                return False

            try:
                # 解析JSON内容
                content_data = json.loads(content_str)

                # 检查contentType是否为2（图片消息）
                if content_data.get('contentType') == 2:
                    return True

                # 检查是否包含image字段
                if 'image' in content_data:
                    return True

                # 检查是否包含pics字段
                if 'image' in content_data and 'pics' in content_data['image']:
                    return True

                return False

            except (json.JSONDecodeError, TypeError):
                # 如果JSON解析失败，检查字符串内容
                if '[图片]' in content_str or 'image' in content_str.lower():
                    return True
                return False

        except Exception as e:
            logger.debug(f"检查图片消息失败: {self._safe_str(e)}")
            return False

    def _is_manual_service_request(self, message: str) -> bool:
        """检测是否为人工客服请求"""
        try:
            # 定义人工客服关键词
            manual_service_keywords = [
                "转人工",
                "人工客服",
                "人工",
                "客服",
                "转接人工",
                "联系客服",
                "找客服",
                "人工服务",
                "转接客服",
                "人工处理",
                "转人工客服"
            ]

            # 检查消息是否包含任何人工客服关键词
            message_lower = message.lower()
            for keyword in manual_service_keywords:
                if keyword in message_lower:
                    logger.info(f"【{self.cookie_id}】检测到人工客服请求关键词: '{keyword}' 在消息: '{message}'")
                    return True

            return False

        except Exception as e:
            logger.error(f"检测人工客服请求失败: {self._safe_str(e)}")
            return False

    def _is_system_message(self, message_content: str, message_data: dict = None) -> bool:
        """检测是否为系统消息"""
        try:
            # 方法1: 检查消息内容格式
            if message_content:
                # 系统消息通常以方括号包围，但排除图片、语音等媒体消息
                if message_content.startswith('[') and message_content.endswith(']'):
                    # 排除媒体消息类型
                    media_message_types = ['[图片]', '[语音]', '[视频]', '[文件]', '[位置]', '[卡片消息]']
                    if message_content not in media_message_types:
                        logger.debug(f"【{self.cookie_id}】检测到方括号系统消息: {message_content}")
                        return True
                
                # 常见的系统消息模式
                system_message_patterns = [
                    '我已拍下，待付款',
                    '已付款，待发货', 
                    '你关闭了订单，钱款已原路退返',
                    # 移除 '发来一条消息' 和 '发来一条新消息' - 这些是推送通知标题，不是消息内容
                    '买家确认收货，交易成功',
                    '快给ta一个评价吧',
                    '卖家人不错？送Ta闲鱼小红花',
                    '你已确认收货，交易成功',
                    '你已发货',
                    '你人真不错，送你闲鱼小红花',
                    '买卖换真心，鼓励你一下',
                    '记得及时发货'
                ]
                
                for pattern in system_message_patterns:
                    if pattern in message_content:
                        logger.debug(f"【{self.cookie_id}】检测到系统消息模式: {pattern}")
                        return True
            
            # 方法2: 检查消息数据结构中的系统标识
            if message_data and isinstance(message_data, dict):
                try:
                    # 检查bizTag中是否包含系统任务标识
                    message_10 = message_data.get('1', {}).get('10', {})
                    if isinstance(message_10, dict):
                        biz_tag = message_10.get('bizTag', '')
                        if biz_tag and isinstance(biz_tag, str):
                            # 尝试解析bizTag JSON
                            try:
                                biz_data = json.loads(biz_tag)
                                # 如果包含taskName，通常是系统消息
                                if 'taskName' in biz_data:
                                    task_name = biz_data.get('taskName', '')
                                    logger.debug(f"【{self.cookie_id}】检测到系统任务消息: {task_name}")
                                    return True
                            except:
                                pass
                        
                        # 检查extJson中的系统标识
                        ext_json = message_10.get('extJson', '')
                        if ext_json and isinstance(ext_json, str):
                            try:
                                ext_data = json.loads(ext_json)
                                # 检查是否有系统消息的特殊标识
                                if 'msgArg1' in ext_data and ext_data['msgArg1'] == 'MsgCard':
                                    logger.debug(f"【{self.cookie_id}】检测到卡片系统消息")
                                    return True
                            except:
                                pass
                        
                        # 检查reminderNotice是否为系统通知
                        reminder_notice = message_10.get('reminderNotice', '')
                        system_notices = [
                            '买家已拍下，待付款',
                            # 移除 '发来一条新消息' - 这是所有用户消息的通用推送标题，不是系统消息标识
                            '买卖换真心，鼓励你一下'
                        ]
                        
                        for notice in system_notices:
                            if notice in reminder_notice:
                                logger.debug(f"【{self.cookie_id}】检测到系统通知: {notice}")
                                return True
                
                except Exception as e:
                    logger.debug(f"检查消息数据结构失败: {self._safe_str(e)}")
            
            return False
            
        except Exception as e:
            logger.error(f"系统消息检测失败: {self._safe_str(e)}")
            return False

    async def _handle_manual_service_request(self, websocket, chat_id: str, send_user_id: str,
                                           send_user_name: str, send_message: str, msg_time: str):
        """处理人工客服转接请求"""
        try:
            safe_user_name = self._safe_encode_data(send_user_name)
            logger.info(f"[{msg_time}] 【{self.cookie_id}】处理人工客服转接请求: 用户 {safe_user_name} (ID: {send_user_id})")

            # 1. 永久暂停该对话的自动回复（转人工后不再自动回复）
            pause_manager.pause_chat_permanently(chat_id, self.cookie_id, "转人工")
            logger.info(f"【{self.cookie_id}】已永久暂停 chat_id {chat_id} 的自动回复（转人工）")

            # 2. 向客户发送转接提示消息
            transfer_message = "请稍等，正在转至人工客服......"
            await self.send_msg(websocket, chat_id, send_user_id, transfer_message)
            safe_transfer_message = self._safe_encode_data(transfer_message)
            logger.info(f"[{msg_time}] 【{self.cookie_id}】已向客户发送转接提示: {safe_transfer_message}")

            # 3. 发送通知给对应账号的wxid
            await self._send_manual_service_notification(send_user_name, send_user_id, send_message, msg_time)

        except Exception as e:
            logger.error(f"处理人工客服转接请求失败: {self._safe_str(e)}")

    async def _send_manual_service_notification(self, send_user_name: str, send_user_id: str,
                                              send_message: str, msg_time: str):
        """发送人工客服通知给wxid"""
        try:
            from db_manager import db_manager

            # 获取当前账号的wxid
            cookie_details = db_manager.get_cookie_details(self.cookie_id)
            if not cookie_details:
                logger.warning(f"【{self.cookie_id}】未找到账号详情，无法发送人工客服通知")
                return

            notification_wxid = cookie_details.get('notification_wxid')
            if not notification_wxid:
                logger.warning(f"【{self.cookie_id}】未配置通知wxid，无法发送人工客服通知")
                return

            # 获取账号备注信息
            account_remark = cookie_details.get('remark', '') if cookie_details else ''

            # 构造通知消息
            notification_msg = f"""🔴 人工客服转接通知

账号ID: {self.cookie_id}"""

            # 如果有备注，添加到通知消息中
            if account_remark:
                notification_msg += f"\n备注: {account_remark}"

            notification_msg += f"""
时间: {msg_time}
客户: {send_user_name} (ID: {send_user_id})
客户消息: {send_message}
用户链接: https://www.goofish.com/personal?userId={send_user_id}

客户请求人工客服，已暂停该对话的自动回复，请及时处理。"""

            logger.info(f"【{self.cookie_id}】准备发送人工客服通知到 wxid: {notification_wxid}")

            # 获取当前账号的通知配置
            notifications = db_manager.get_message_notifications(self.cookie_id)

            if not notifications:
                logger.warning(f"【{self.cookie_id}】未配置消息通知渠道，无法发送人工客服通知")
                return

            # 发送通知到各个渠道
            notification_sent = False
            for notification in notifications:
                if not notification.get('enabled', True):
                    continue

                channel_type = notification.get('channel_type')
                channel_config = notification.get('config')

                if channel_config:
                    try:
                        config_data = json.loads(channel_config)
                    except:
                        config_data = {}

                    if channel_type in ['ding_talk', 'dingtalk']:
                        await self._send_dingtalk_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'email':
                        await self._send_email_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'webhook':
                        await self._send_webhook_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'wechat':
                        await self._send_wechat_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'telegram':
                        await self._send_telegram_notification(config_data, notification_msg)
                        notification_sent = True
                    else:
                        logger.warning(f"不支持的通知渠道类型: {channel_type}")

            if notification_sent:
                logger.info(f"【{self.cookie_id}】人工客服通知发送成功")
            else:
                logger.warning(f"【{self.cookie_id}】人工客服通知发送失败，没有可用的通知渠道")

        except Exception as e:
            logger.error(f"发送人工客服通知失败: {self._safe_str(e)}")

    async def _handle_blacklist_request(self, websocket, chat_id: str, send_user_id: str, 
                                      send_user_name: str, msg_time: str):
        """处理拉黑请求（接收到的拉黑指令）"""
        try:
            from utils.xianyu_utils import blacklist_user
            from db_manager import db_manager
            
            logger.info(f"[{msg_time}] 【{self.cookie_id}】收到拉黑指令，准备拉黑用户: {send_user_name} (ID: {send_user_id})")
            
            # 调用拉黑接口，使用chat_id作为sessionId
            success = await blacklist_user(chat_id, self.cookies_str)
            
            if success:
                # 拉黑成功，记录到数据库
                db_manager.add_blacklist_record(
                    cookie_id=self.cookie_id,
                    session_id=chat_id,
                    user_id=send_user_id,
                    user_name=send_user_name,
                    reason="主动拉黑"
                )
                
                # 发送确认消息
                await self.send_msg(websocket, chat_id, send_user_id, "已成功拉黑该用户")
                logger.info(f"[{msg_time}] 【{self.cookie_id}】✅ 用户拉黑成功: {send_user_name} (ID: {send_user_id})")
                
                # 发送通知
                await self.send_notification(
                    send_user_name=send_user_name,
                    send_user_id=send_user_id,
                    send_message=f"用户 {send_user_name} (ID: {send_user_id}) 已被成功拉黑"
                )
            else:
                # 拉黑失败
                await self.send_msg(websocket, chat_id, send_user_id, "拉黑失败，请稍后重试")
                logger.error(f"[{msg_time}] 【{self.cookie_id}】❌ 用户拉黑失败: {send_user_name} (ID: {send_user_id})")
                
        except Exception as e:
            logger.error(f"[{msg_time}] 【{self.cookie_id}】处理拉黑请求时发生异常: {self._safe_str(e)}")
            try:
                await self.send_msg(websocket, chat_id, send_user_id, "拉黑操作异常，请稍后重试")
            except:
                pass

    async def _handle_manual_blacklist_request(self, websocket, chat_id: str, msg_time: str):
        """处理手动发出的拉黑请求"""
        try:
            from utils.xianyu_utils import blacklist_user
            from db_manager import db_manager
            
            logger.info(f"[{msg_time}] 【{self.cookie_id}】检测到手动发出的拉黑指令，准备拉黑会话: {chat_id}")
            
            # 调用拉黑接口，使用chat_id作为sessionId
            success = await blacklist_user(chat_id, self.cookies_str)
            
            if success:
                # 拉黑成功，记录到数据库
                # 对于手动拉黑，我们只有chat_id，用户信息设置为未知
                db_manager.add_blacklist_record(
                    cookie_id=self.cookie_id,
                    session_id=chat_id,
                    user_id="unknown",
                    user_name="手动拉黑用户",
                    reason="手动拉黑"
                )
                
                logger.info(f"[{msg_time}] 【{self.cookie_id}】✅ 手动拉黑成功: 会话 {chat_id}")
                
                # 发送通知
                await self.send_notification(
                    send_user_name="手动拉黑用户",
                    send_user_id="unknown",
                    send_message=f"会话 {chat_id} 已被手动拉黑"
                )
            else:
                # 拉黑失败
                logger.error(f"[{msg_time}] 【{self.cookie_id}】❌ 手动拉黑失败: 会话 {chat_id}")
                
        except Exception as e:
            logger.error(f"[{msg_time}] 【{self.cookie_id}】处理手动拉黑请求时发生异常: {self._safe_str(e)}")

    async def _check_and_trigger_auto_delivery(self, websocket, order_id: str, item_id: str, user_id: str, msg_time: str):
        """检查并触发自动发货（用于订单创建后的异步检查）"""
        try:
            # 首先检查用户余额是否足够进行自动发货操作
            from db_manager import db_manager
            cookie_user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
            
            if cookie_user_id:
                current_balance = db_manager.get_user_balance(cookie_user_id)
                if current_balance < 3.0:
                    logger.warning(f"[{msg_time}] 【{self.cookie_id}】用户余额不足(当前:{current_balance}聚合豆，需要:3聚合豆)，跳过自动发货操作")
                    return
            else:
                logger.error(f"[{msg_time}] 【{self.cookie_id}】无法获取用户ID，跳过自动发货操作")
                return
            # 检查是否可以进行自动发货（防重复）- 基于订单ID
            if not self.can_auto_delivery(order_id):
                logger.info(f"[{msg_time}] 【{self.cookie_id}】订单 {order_id} 已处理过或在冷却期，跳过自动发货")
                return

            # 检查订单是否已经发货（防止重复发货）
            if order_id:
                try:
                    logger.info(f"[{msg_time}] 【{self.cookie_id}】检查订单是否已经发货: {order_id}")
                    existing_order = db_manager.get_order_by_id(order_id, self.cookie_id)
                    if existing_order and existing_order.get('order_status') == '已发货':
                        logger.warning(f"[{msg_time}] 【{self.cookie_id}】❌ 订单 {order_id} 已经发货，跳过重复发货")
                        return
                    logger.info(f"[{msg_time}] 【{self.cookie_id}】✅ 订单 {order_id} 未发货或不存在，可以继续发货")
                except Exception as e:
                    logger.warning(f"[{msg_time}] 【{self.cookie_id}】检查订单状态失败: {self._safe_str(e)}，继续发货流程")

            # 标记订单开始处理（防止并发）
            if order_id:
                self.mark_delivery_processing(order_id)

            # 获取用户信息（从数据库或其他方式）
            user_url = f'https://www.goofish.com/personal?userId={user_id}'
            
            # 设置默认标题（将通过API获取真实商品信息）
            item_title = "待获取商品信息"

            logger.info(f"[{msg_time}] 【{self.cookie_id}】订单创建后自动发货检查: order_id={order_id}, item_id={item_id}")

            # 调用自动发货方法（包含自动确认发货）
            delivery_content = await self._auto_delivery(item_id, item_title, order_id)

            if delivery_content:
                # 标记已发货（防重复）- 基于订单ID
                self.mark_delivery_sent(order_id)

                # 构造聊天ID（使用用户ID作为聊天ID）
                chat_id = user_id

                # 处理不同类型的发货内容
                send_success = False
                card_id_to_consume = None
                
                if delivery_content.startswith("__IMAGE_WITH_NOTE__"):
                    # 图片+备注分开发送
                    image_data = delivery_content.replace("__IMAGE_WITH_NOTE__", "")
                    parts = image_data.split("|", 2)
                    if len(parts) >= 3:
                        card_id_str, image_url, card_description = parts[0], parts[1], parts[2]
                        try:
                            card_id = int(card_id_str)
                        except ValueError:
                            logger.error(f"无效的卡券ID: {card_id_str}")
                            card_id = None

                        try:
                            # 先发送图片
                            await self.send_image_msg(websocket, chat_id, user_id, image_url, card_id=card_id)
                            logger.info(f'[{msg_time}] 【自动发货图片】已向 {user_url} 发送图片: {image_url}')
                            
                            # 再发送备注信息
                            if card_description and card_description.strip():
                                # 添加短暂延迟，确保图片和备注消息分开显示
                                await asyncio.sleep(1)
                                # 处理备注中的变量替换
                                processed_description = card_description.replace('{DELIVERY_CONTENT}', '图片卡券')
                                await self.send_msg(websocket, chat_id, user_id, processed_description)
                                logger.info(f'[{msg_time}] 【自动发货备注】已向 {user_url} 发送备注: {processed_description}')
                            
                            send_success = True
                        except Exception as e:
                            logger.error(f"自动发货图片或备注失败: {self._safe_str(e)}")
                            await self.send_msg(websocket, chat_id, user_id, "抱歉，发送失败，请联系客服。")
                    else:
                        logger.error(f"图片+备注格式错误: {delivery_content}")
                        
                elif delivery_content.startswith("__IMAGE_SEND__"):
                    # 传统图片发送标记
                    image_data = delivery_content.replace("__IMAGE_SEND__", "")
                    if "|" in image_data:
                        card_id_str, image_url = image_data.split("|", 1)
                        try:
                            card_id = int(card_id_str)
                        except ValueError:
                            logger.error(f"无效的卡券ID: {card_id_str}")
                            card_id = None
                    else:
                        card_id = None
                        image_url = image_data

                    try:
                        await self.send_image_msg(websocket, chat_id, user_id, image_url, card_id=card_id)
                        logger.info(f'[{msg_time}] 【自动发货图片】已向 {user_url} 发送图片: {image_url}')
                        send_success = True
                    except Exception as e:
                        logger.error(f"自动发货图片失败: {self._safe_str(e)}")
                        await self.send_msg(websocket, chat_id, user_id, "抱歉，图片发送失败，请联系客服。")
                        
                elif delivery_content.startswith("__BATCH_DATA_IMAGE_WITH_NOTE__"):
                    # 批量数据图片+备注分开发送
                    parts = delivery_content.replace("__BATCH_DATA_IMAGE_WITH_NOTE__", "").split("|")
                    if len(parts) >= 4:
                        card_id_str, image_url, actual_data, card_description = parts[0], parts[1], parts[2], parts[3]
                        try:
                            card_id = int(card_id_str)
                            card_id_to_consume = card_id
                        except ValueError:
                            logger.error(f"无效的卡券ID: {card_id_str}")
                            card_id = None

                        try:
                            # 先发送图片
                            await self.send_image_msg(websocket, chat_id, user_id, image_url, card_id=card_id)
                            logger.info(f'[{msg_time}] 【自动发货图片】已向 {user_url} 发送图片: {image_url}')
                            
                            # 再发送备注信息
                            if card_description and card_description.strip():
                                # 添加短暂延迟，确保图片和备注消息分开显示
                                await asyncio.sleep(1)
                                # 处理备注中的变量替换
                                processed_description = card_description.replace('{DELIVERY_CONTENT}', actual_data)
                                await self.send_msg(websocket, chat_id, user_id, processed_description)
                                logger.info(f'[{msg_time}] 【自动发货备注】已向 {user_url} 发送备注: {processed_description}')
                            
                            send_success = True
                        except Exception as e:
                            logger.error(f"自动发货图片或备注失败: {self._safe_str(e)}")
                            # 图片发送失败，发送文本
                            try:
                                await self.send_msg(websocket, chat_id, user_id, actual_data)
                                logger.info(f'[{msg_time}] 【自动发货文本】图片失败后发送文本: {actual_data}')
                                send_success = True
                            except Exception as text_e:
                                logger.error(f"发送文本也失败: {self._safe_str(text_e)}")
                    else:
                        logger.error(f"批量数据图片+备注格式错误: {delivery_content}")
                        
                elif delivery_content.startswith("__BATCH_DATA_IMAGE__"):
                    # 批量数据生成的图片（无备注）
                    parts = delivery_content.replace("__BATCH_DATA_IMAGE__", "").split("|")
                    if len(parts) >= 3:
                        card_id_str, image_url, actual_data = parts[0], parts[1], parts[2]
                        try:
                            card_id = int(card_id_str)
                            card_id_to_consume = card_id
                        except ValueError:
                            logger.error(f"无效的卡券ID: {card_id_str}")
                            card_id = None

                        try:
                            await self.send_image_msg(websocket, chat_id, user_id, image_url, card_id=card_id)
                            logger.info(f'[{msg_time}] 【自动发货图片】已向 {user_url} 发送图片: {image_url}')
                            send_success = True
                        except Exception as e:
                            logger.error(f"自动发货图片失败: {self._safe_str(e)}")
                            # 图片发送失败，发送文本
                            try:
                                await self.send_msg(websocket, chat_id, user_id, actual_data)
                                logger.info(f'[{msg_time}] 【自动发货文本】图片失败后发送文本: {actual_data}')
                                send_success = True
                            except Exception as text_e:
                                logger.error(f"发送文本也失败: {self._safe_str(text_e)}")
                                
                elif delivery_content.startswith("__BATCH_DATA__"):
                    # 批量数据文本
                    parts = delivery_content.replace("__BATCH_DATA__", "").split("|", 1)
                    if len(parts) == 2:
                        card_id_str, actual_data = parts
                        try:
                            card_id_to_consume = int(card_id_str)
                        except ValueError:
                            logger.error(f"无效的卡券ID: {card_id_str}")

                        try:
                            await self.send_msg(websocket, chat_id, user_id, actual_data)
                            logger.info(f'[{msg_time}] 【自动发货文本】已向 {user_url} 发送: {actual_data}')
                            send_success = True
                        except Exception as e:
                            logger.error(f"自动发货文本失败: {self._safe_str(e)}")
                else:
                    # 普通文本消息
                    try:
                        await self.send_msg(websocket, chat_id, user_id, delivery_content)
                        logger.info(f'[{msg_time}] 【自动发货文本】已向 {user_url} 发送: {delivery_content}')
                        send_success = True
                    except Exception as e:
                        logger.error(f"自动发货文本失败: {self._safe_str(e)}")
                
                # 只有在发送成功后才消费卡券
                if send_success and card_id_to_consume:
                    try:
                        from db_manager import db_manager
                        consumed_data = db_manager.consume_batch_data(card_id_to_consume)
                        if consumed_data:
                            logger.info(f"发送成功后消费卡券: 卡券ID={card_id_to_consume}, 消费内容={consumed_data}")
                        else:
                            logger.warning(f"卡券消费失败: 卡券ID={card_id_to_consume}")
                    except Exception as e:
                        logger.error(f"消费卡券异常: {self._safe_str(e)}")
            else:
                logger.info(f"[{msg_time}] 【{self.cookie_id}】未找到匹配的发货规则: item_id={item_id}")

        except Exception as e:
            logger.error(f"[{msg_time}] 【{self.cookie_id}】订单创建后自动发货检查失败: {self._safe_str(e)}")
            # 异常时清理处理锁
            if order_id:
                self.unmark_delivery_processing(order_id)

    async def _handle_auto_delivery(self, websocket, message: dict, send_user_name: str, send_user_id: str,
                                   item_id: str, chat_id: str, msg_time: str):
        """统一处理自动发货逻辑 - 优化版本"""
        try:
            # 首先检查用户余额是否足够进行自动发货操作
            from db_manager import db_manager
            user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
            
            if user_id:
                current_balance = db_manager.get_user_balance(user_id)
                if current_balance < 3.0:
                    logger.warning(f"[{msg_time}] 【{self.cookie_id}】用户余额不足(当前:{current_balance}聚合豆，需要:3聚合豆)，跳过自动发货操作")
                    return
            else:
                logger.error(f"[{msg_time}] 【{self.cookie_id}】无法获取用户ID，跳过自动发货操作")
                return
            # 提取订单ID
            order_id = self._extract_order_id(message)

            # 订单ID已提取，将在自动发货时进行确认发货处理
            if order_id:
                logger.info(f'[{msg_time}] 【{self.cookie_id}】提取到订单ID: {order_id}，将在自动发货时处理确认发货')
            else:
                logger.warning(f'[{msg_time}] 【{self.cookie_id}】❌ 未能提取到订单ID')

            # 检查是否可以进行自动发货（防重复）- 基于订单ID
            if not self.can_auto_delivery(order_id):
                logger.info(f'[{msg_time}] 【{self.cookie_id}】订单 {order_id} 已处理过或在冷却期，跳过自动发货')
                return

            # 标记订单开始处理（防止并发）
            if order_id:
                self.mark_delivery_processing(order_id)

            # 构造用户URL
            user_url = f'https://www.goofish.com/personal?userId={send_user_id}'

            # 自动发货逻辑
            try:
                # 设置默认标题（将通过API获取真实商品信息）
                item_title = "待获取商品信息"

                logger.info(f"【{self.cookie_id}】准备自动发货: item_id={item_id}, item_title={item_title}")

                # 步骤0: 预检查发货规则 - 避免不必要的订单详情获取
                logger.info(f"[{msg_time}] 【步骤0】预检查是否有发货规则")
                
                from db_manager import db_manager
                
                # 获取当前cookie的用户ID
                try:
                    cookie_info = db_manager.get_cookie_by_id(self.cookie_id)
                    current_user_id = cookie_info.get('user_id') if cookie_info else None
                    logger.debug(f"[{msg_time}] 【步骤0】当前用户ID: {current_user_id}")
                except Exception as e:
                    logger.warning(f"[{msg_time}] 【步骤0】获取用户ID失败: {self._safe_str(e)}")
                    current_user_id = None
                
                # 快速检查是否有任何发货规则（包括多规格和普通规则）
                all_delivery_rules = db_manager.get_delivery_rules_by_item_id(item_id, current_user_id)
                
                if not all_delivery_rules:
                    logger.warning(f"[{msg_time}] 【步骤0】❌ 商品ID {item_id} 没有任何发货规则，跳过自动发货")
                    return
                
                logger.info(f"[{msg_time}] 【步骤0】✅ 找到 {len(all_delivery_rules)} 个发货规则，继续处理")

                # 步骤0.5: 检查订单是否已经发货（防止重复发货）
                if order_id:
                    try:
                        logger.info(f"[{msg_time}] 【步骤0.5】检查订单是否已经发货: {order_id}")
                        existing_order = db_manager.get_order_by_id(order_id, self.cookie_id)
                        if existing_order and existing_order.get('order_status') == '已发货':
                            logger.warning(f"[{msg_time}] 【步骤0.5】❌ 订单 {order_id} 已经发货，跳过重复发货")
                            return
                        logger.info(f"[{msg_time}] 【步骤0.5】✅ 订单 {order_id} 未发货或不存在，可以继续发货")
                    except Exception as e:
                        logger.warning(f"[{msg_time}] 【步骤0.5】检查订单状态失败: {self._safe_str(e)}，继续发货流程")

                # 步骤1: 获取订单详情中的数量（仅在有发货规则时执行）
                order_quantity = 1  # 默认数量为1
                order_detail_result = None  # 用于存储订单详情，供后续步骤使用
                if order_id:
                    try:
                        logger.info(f"[{msg_time}] 【步骤1】获取订单详情中的数量: {order_id}")
                        
                        # 首先检查数据库中是否已有完整的订单详情
                        existing_order = db_manager.get_order_by_id_enhanced(order_id)
                        if existing_order and existing_order.get('quantity'):
                            try:
                                order_quantity = int(existing_order['quantity'])
                                logger.info(f"[{msg_time}] 【步骤1】✅ 从数据库获取订单数量: {order_quantity}")
                            except (ValueError, TypeError):
                                logger.warning(f"[{msg_time}] 【步骤1】⚠️ 数据库订单数量格式无效: {existing_order.get('quantity')}，继续获取详情")
                                existing_order = None
                        
                        # 如果数据库中没有完整信息，则获取订单详情
                        if not existing_order or not existing_order.get('quantity'):
                            logger.info(f"[{msg_time}] 【步骤1】数据库中无完整订单信息，开始获取订单详情")
                            
                            # 等待订单详情获取完成，最多等待30秒
                            max_wait_time = 30
                            wait_interval = 1
                            waited_time = 0
                            
                            order_detail = None
                            while waited_time < max_wait_time:
                                # 检查是否有其他进程正在获取订单详情
                                lock_key = f"{self.cookie_id}_{order_id}"
                                if lock_key in self._order_detail_locks:
                                    logger.info(f"[{msg_time}] 【步骤1】等待订单详情获取完成... ({waited_time}s/{max_wait_time}s)")
                                    await asyncio.sleep(wait_interval)
                                    waited_time += wait_interval
                                    
                                    # 检查数据库是否已更新
                                    updated_order = db_manager.get_order_by_id_enhanced(order_id)
                                    if updated_order and updated_order.get('quantity'):
                                        try:
                                            order_quantity = int(updated_order['quantity'])
                                            logger.info(f"[{msg_time}] 【步骤1】✅ 等待期间从数据库获取到数量: {order_quantity}")
                                            break
                                        except (ValueError, TypeError):
                                            pass
                                else:
                                    # 没有其他进程在获取，直接获取
                                    order_detail_result = await self.fetch_order_detail_info(order_id, item_id, send_user_id)
                                    order_detail = order_detail_result  # 保持兼容性
                                    break
                            
                            # 如果通过等待获取到了数量，就不需要再处理order_detail了
                            if order_quantity == 1 and order_detail and order_detail.get('quantity'):
                                try:
                                    order_quantity = int(order_detail['quantity'])
                                    logger.info(f"[{msg_time}] 【步骤1】✅ 从订单详情获取数量: {order_quantity}")
                                except (ValueError, TypeError):
                                    logger.warning(f"[{msg_time}] 【步骤1】⚠️ 订单数量格式无效: {order_detail.get('quantity')}，使用默认数量1")
                                    order_quantity = 1
                            elif order_quantity == 1:
                                logger.info(f"[{msg_time}] 【步骤1】⚠️ 等待超时或未获取到订单数量信息，使用默认数量1")
                                order_quantity = 1
                            
                            # 确保order_detail_result被正确赋值
                            if order_detail and not order_detail_result:
                                order_detail_result = order_detail
                                logger.debug(f"[{msg_time}] 【步骤1】🔍 确保order_detail_result被赋值")
                    except Exception as e:
                        logger.error(f"[{msg_time}] 【步骤1】❌ 获取订单详情失败: {self._safe_str(e)}，使用默认数量1")
                        order_quantity = 1

                # 步骤2: 检查发货规则和库存（支持多规格匹配）
                logger.info(f"[{msg_time}] 【步骤2】检查发货规则和库存")
                
                # 获取订单的规格信息用于匹配
                order_spec_name = None
                order_spec_value = None
                
                # 尝试从数据库获取订单规格信息
                try:
                    existing_order = db_manager.get_order_by_id_enhanced(order_id)
                    if existing_order:
                        order_spec_name = existing_order.get('spec_name')
                        order_spec_value = existing_order.get('spec_value')
                        if order_spec_name and order_spec_value:
                            logger.info(f"[{msg_time}] 【步骤2】📋 从数据库获取订单规格: {order_spec_name} = {order_spec_value}")
                        else:
                            logger.info(f"[{msg_time}] 【步骤2】📋 订单无规格信息，使用普通匹配")
                except Exception as e:
                    logger.error(f"[{msg_time}] 【步骤2】获取订单规格信息失败: {self._safe_str(e)}")
                
                # 如果数据库中没有订单规格信息，尝试从第1步获取的订单详情中获取
                logger.debug(f"[{msg_time}] 【步骤2】🔍 调试信息: order_detail_result = {order_detail_result}")
                if not (order_spec_name and order_spec_value) and order_detail_result:
                    order_spec_name = order_detail_result.get('spec_name')
                    order_spec_value = order_detail_result.get('spec_value')
                    if order_spec_name and order_spec_value:
                        logger.info(f"[{msg_time}] 【步骤2】📋 从订单详情获取规格: {order_spec_name} = {order_spec_value}")
                    else:
                        logger.info(f"[{msg_time}] 【步骤2】📋 订单详情中无规格信息，使用普通匹配")
                        logger.debug(f"[{msg_time}] 【步骤2】🔍 订单详情内容: {order_detail_result}")
                elif not (order_spec_name and order_spec_value):
                    logger.info(f"[{msg_time}] 【步骤2】📋 无订单详情或数据库规格信息，使用普通匹配")
                
                # 智能匹配发货规则：优先精确匹配多规格，然后兜底匹配普通规则
                delivery_rules = []
                
                # 如果有规格信息，先尝试精确匹配多规格发货规则
                if order_spec_name and order_spec_value:
                    logger.info(f"[{msg_time}] 【步骤2】🎯 尝试精确匹配多规格发货规则: 商品ID={item_id}, [{order_spec_name}:{order_spec_value}]")
                    
                    # 从所有发货规则中筛选匹配的多规格规则
                    delivery_rules = [rule for rule in all_delivery_rules 
                                    if rule.get('rule_is_multi_spec') 
                                    and rule.get('rule_spec_name') == order_spec_name 
                                    and rule.get('rule_spec_value') == order_spec_value]
                    
                    if delivery_rules:
                        logger.info(f"[{msg_time}] 【步骤2】✅ 找到精确匹配的多规格发货规则: {len(delivery_rules)}个")
                    else:
                        logger.info(f"[{msg_time}] 【步骤2】❌ 未找到精确匹配的多规格发货规则，尝试兜底匹配")
                
                # 如果没有找到多规格匹配或没有规格信息，使用普通匹配（兜底）
                if not delivery_rules:
                    logger.info(f"[{msg_time}] 【步骤2】🔄 使用普通发货规则匹配")
                    
                    # 只使用普通发货规则（非多规格）作为兜底
                    delivery_rules = [rule for rule in all_delivery_rules if not rule.get('rule_is_multi_spec')]
                    if delivery_rules:
                        logger.info(f"[{msg_time}] 【步骤2】✅ 找到 {len(delivery_rules)} 个普通发货规则作为兜底")
                    else:
                        logger.info(f"[{msg_time}] 【步骤2】❌ 未找到普通发货规则，无法兜底")
                
                if not delivery_rules:
                    logger.warning(f"[{msg_time}] 【步骤2】❌ 未找到匹配的发货规则")
                    return
                
                # 检查第一个匹配规则的库存（不消费数据）
                rule = delivery_rules[0]
                
                # 显示使用的发货规则信息
                rule_info = f"卡券: {rule.get('card_name', '未知')}"
                if rule.get('rule_is_multi_spec') and rule.get('rule_spec_name') and rule.get('rule_spec_value'):
                    rule_info += f" [多规格发货: {rule['rule_spec_name']}={rule['rule_spec_value']}]"
                    if order_spec_name and order_spec_value:
                        if rule['rule_spec_name'] == order_spec_name and rule['rule_spec_value'] == order_spec_value:
                            rule_info += " ✅匹配"
                        else:
                            rule_info += f" ⚠️不匹配(订单: {order_spec_name}={order_spec_value})"
                else:
                    rule_info += " [普通发货规则]"
                
                logger.info(f"[{msg_time}] 【步骤2】🎯 使用发货规则: {rule_info}")
                if rule.get('card_type') == 'data':
                    # 对于批量数据类型，检查是否有库存
                    card_data = self._peek_batch_data(rule['card_id'])
                    if not card_data:
                        logger.warning(f"[{msg_time}] 【步骤2】❌ 发货规则存在但卡券无库存")
                        await self.send_msg(websocket, chat_id, send_user_id, "抱歉，商品暂时缺货，请联系客服。")
                        return
                
                logger.info(f"[{msg_time}] 【步骤2】✅ 发货规则和库存检查通过")

                # 获取发货数量（使用已获取的规则）
                rule_delivery_count = rule.get('delivery_count', 1)
                logger.info(f"[{msg_time}] 【步骤2】✅ 发货规则的发货数量: {rule_delivery_count}")

                # 步骤3: 计算实际发送卡券数量 = 订单数量 × 发货数量
                actual_send_quantity = order_quantity * rule_delivery_count
                logger.info(f"[{msg_time}] 【步骤3】计算实际发送数量: {order_quantity} × {rule_delivery_count} = {actual_send_quantity}")

                # 检查是否为API类型卡券，如果是则单独处理
                if rule['card_type'] == 'api':
                    # API类型：调用JH API获取卡券列表，一次性获取所需数量的卡券
                    logger.info(f"[{msg_time}] 【步骤4】调用JH API获取 {actual_send_quantity} 张卡券")
                    coupon_list, total_cost = await self._get_api_card_content(rule, order_id, actual_send_quantity)
                    
                    if coupon_list and len(coupon_list) > 0:
                        logger.info(f"[{msg_time}] 【步骤4】✅ JH API返回 {len(coupon_list)} 张卡券，总成本: {total_cost}")
                        
                        # 检查是否需要生成美化图片
                        generate_image = rule.get('generate_image', True)
                        
                        # 直接在这里处理所有卡券的发送
                        success_count = 0
                        failed_count = 0
                        consumed_coupon_codes = []  # 记录所有消费的券码
                        actual_data_list = []  # 记录所有实际数据，用于备注变量替换
                        
                        # 获取卡券描述信息
                        card_description_to_send = rule.get('card_description', '')
                        
                        # 标记已发货（防重复）- 基于订单ID
                        self.mark_delivery_sent(order_id)
                        
                        for i, coupon_data in enumerate(coupon_list[:actual_send_quantity]):
                            try:
                                logger.info(f"[{msg_time}] 【步骤4】发送第 {i+1}/{len(coupon_list)} 个JH API卡券")
                                
                                # 记录券码信息用于订单保存
                                consumed_coupon_codes.append(str(coupon_data))
                                actual_data_list.append(str(coupon_data))
                                
                                if generate_image:
                                    # 生成美化图片并发送
                                    try:
                                        from GenerateCoupon import gm_main
                                        image_path = gm_main(str(coupon_data))
                                        
                                        if image_path and os.path.exists(image_path):
                                            # 移动图片到uploads目录
                                            import shutil
                                            upload_dir = "static/uploads"
                                            os.makedirs(upload_dir, exist_ok=True)
                                            
                                            import uuid
                                            file_extension = os.path.splitext(image_path)[1]
                                            new_filename = f"jh_coupon_{uuid.uuid4().hex[:8]}{file_extension}"
                                            new_image_path = os.path.join(upload_dir, new_filename)
                                            shutil.move(image_path, new_image_path)
                                            
                                            # 标准化路径格式
                                            normalized_path = new_image_path.replace('\\', '/')
                                            
                                            # 发送图片
                                            await self.send_image_msg(websocket, chat_id, send_user_id, normalized_path)
                                            logger.info(f'[{msg_time}] 【JH API图片】第 {i+1} 个已向 {user_url} 发送图片: {normalized_path}')
                                            success_count += 1
                                        else:
                                            # 图片生成失败，发送文本
                                            await self.send_msg(websocket, chat_id, send_user_id, str(coupon_data))
                                            logger.info(f'[{msg_time}] 【JH API文本】第 {i+1} 个图片生成失败，发送文本: {coupon_data}')
                                            success_count += 1
                                    except Exception as e:
                                        logger.error(f"第 {i+1} 个JH API图片生成失败: {self._safe_str(e)}")
                                        # 图片生成失败，发送文本
                                        try:
                                            await self.send_msg(websocket, chat_id, send_user_id, str(coupon_data))
                                            logger.info(f'[{msg_time}] 【JH API文本】第 {i+1} 个图片生成失败，发送文本: {coupon_data}')
                                            success_count += 1
                                        except Exception as text_e:
                                            logger.error(f"第 {i+1} 个JH API文本发送也失败: {self._safe_str(text_e)}")
                                            failed_count += 1
                                else:
                                    # 直接发送文本
                                    try:
                                        await self.send_msg(websocket, chat_id, send_user_id, str(coupon_data))
                                        logger.info(f'[{msg_time}] 【JH API文本】第 {i+1} 个已向 {user_url} 发送: {coupon_data}')
                                        success_count += 1
                                    except Exception as e:
                                        logger.error(f"第 {i+1} 个JH API文本发送失败: {self._safe_str(e)}")
                                        failed_count += 1
                                
                                # 在发送多个卡券时添加间隔，避免发送过快
                                if i < len(coupon_list) - 1:
                                    await asyncio.sleep(0.5)
                                    
                            except Exception as e:
                                logger.error(f"第 {i+1} 个JH API卡券处理异常: {self._safe_str(e)}")
                                failed_count += 1
                        
                        # JH API卡券发送完成后的处理
                        if success_count > 0:
                            # 扣除自动发货费用
                            user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
                            if user_id:
                                balance_sufficient = db_manager.check_and_consume_balance(
                                    user_id=user_id,
                                    amount=10.0,
                                    description=f"JH API自动发货 - 商品ID:{item_id}, 规则ID:{rule['id']}",
                                    order_id=order_id
                                )
                                if balance_sufficient:
                                    logger.info(f"[{msg_time}] 【JH API自动发货扣费】成功扣除10聚合豆，用户ID:{user_id}")
                                    db_manager.increment_delivery_times(rule['id'])
                            
                            # 发送卡券备注信息（如果有）
                            if card_description_to_send and card_description_to_send.strip():
                                try:
                                    # 添加短暂延迟，确保卡券和备注消息分开显示
                                    await asyncio.sleep(1)
                                    
                                    # 处理备注中的变量替换
                                    if '{DELIVERY_CONTENT}' in card_description_to_send:
                                        # 如果备注中包含变量，使用所有实际数据的组合
                                        combined_data = "; ".join(actual_data_list) if actual_data_list else ""
                                        processed_description = card_description_to_send.replace('{DELIVERY_CONTENT}', combined_data)
                                    else:
                                        processed_description = card_description_to_send
                                    
                                    await self.send_msg(websocket, chat_id, send_user_id, processed_description)
                                    logger.info(f'[{msg_time}] 【JH API备注】已向 {user_url} 发送备注: {processed_description}')
                                except Exception as e:
                                    logger.error(f"发送JH API备注失败: {self._safe_str(e)}")
                            
                            # 保存订单信息
                            try:
                                from datetime import datetime
                                
                                # 获取订单详情信息（数量、金额、规格等）
                                order_detail_info = None
                                try:
                                    # 先尝试使用步骤1中已获取的订单详情
                                    if order_detail_result:
                                        order_detail_info = order_detail_result
                                        logger.info(f"[{msg_time}] 【JH API订单】使用步骤1已获取的订单详情")
                                    else:
                                        # 从数据库查找现有订单信息
                                        existing_order = db_manager.get_order_by_id_enhanced(order_id)
                                        if existing_order and (existing_order.get('quantity') or existing_order.get('amount')):
                                            order_detail_info = existing_order
                                            logger.info(f"[{msg_time}] 【JH API订单】从数据库获取订单信息")
                                        else:
                                            # 如果都没有，重新获取订单详情
                                            order_detail_info = await self.fetch_order_detail_info(order_id, item_id, send_user_id)
                                            logger.info(f"[{msg_time}] 【JH API订单】重新获取订单详情信息")
                                except Exception as detail_e:
                                    logger.warning(f"[{msg_time}] 【JH API订单】获取订单详情失败: {self._safe_str(detail_e)}")
                                
                                # 更新订单状态为已发货，并记录券码信息
                                coupon_codes_str = "; ".join(consumed_coupon_codes) if consumed_coupon_codes else None
                                order_data = {
                                    'order_id': order_id,
                                    'buyer_id': send_user_id,
                                    'buyer_name': send_user_name,  # 添加买家名称
                                    'item_id': item_id,
                                    'order_status': '已发货',
                                    'shipping_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                                    'coupon_code': coupon_codes_str,  # 记录所有券码信息
                                    'raw_message': f"JH API自动发货成功 - 发送{success_count}个卡券 - {msg_time}"
                                }
                                
                                # 如果获取到了订单详情，添加数量和金额信息
                                if order_detail_info:
                                    if order_detail_info.get('quantity'):
                                        order_data['quantity'] = order_detail_info['quantity']
                                        logger.info(f"[{msg_time}] 【JH API订单】添加数量信息: {order_detail_info['quantity']}")
                                    
                                    if order_detail_info.get('amount'):
                                        order_data['amount'] = order_detail_info['amount']
                                        logger.info(f"[{msg_time}] 【JH API订单】添加金额信息: {order_detail_info['amount']}")
                                    
                                    # 添加规格信息
                                    if order_detail_info.get('spec_name'):
                                        order_data['spec_name'] = order_detail_info['spec_name']
                                    if order_detail_info.get('spec_value'):
                                        order_data['spec_value'] = order_detail_info['spec_value']
                                
                                success = db_manager.save_order(self.cookie_id, order_data)
                                if success:
                                    logger.info(f"[{msg_time}] 【JH API订单】订单状态更新成功: {order_id} -> 已发货")
                                    
                                    # 检查是否启用自动确认发货
                                    if self.is_auto_confirm_enabled():
                                        try:
                                            # 检查确认发货冷却时间
                                            current_time = time.time()
                                            should_confirm = True

                                            if order_id in self.confirmed_orders:
                                                last_confirm_time = self.confirmed_orders[order_id]
                                                if current_time - last_confirm_time < self.order_confirm_cooldown:
                                                    logger.info(f"[{msg_time}] 【JH API自动确认发货】订单 {order_id} 已在 {self.order_confirm_cooldown} 秒内确认过，跳过重复确认")
                                                    should_confirm = False

                                            if should_confirm:
                                                logger.info(f"[{msg_time}] 【JH API自动确认发货】开始确认发货: 订单ID={order_id}")
                                                confirm_result = await self.auto_confirm(order_id, item_id)
                                                if confirm_result.get('success'):
                                                    self.confirmed_orders[order_id] = current_time
                                                    logger.info(f"[{msg_time}] 🎉 【JH API自动确认发货】确认发货成功！订单ID: {order_id}")
                                                else:
                                                    logger.warning(f"[{msg_time}] ⚠️ 【JH API自动确认发货】确认发货失败: {confirm_result.get('error', '未知错误')}")
                                        except Exception as confirm_e:
                                            logger.error(f"[{msg_time}] 【JH API自动确认发货】确认发货异常: {self._safe_str(confirm_e)}")
                                    else:
                                        logger.info(f"[{msg_time}] 【JH API自动确认发货】自动确认发货已关闭，跳过订单 {order_id}")
                                else:
                                    logger.error(f"[{msg_time}] 【JH API订单】订单状态更新失败: {order_id}")
                            except Exception as e:
                                logger.error(f"[{msg_time}] 【JH API订单】保存订单信息失败: {self._safe_str(e)}")
                        
                        # 如果有成功发送的卡券，检查成本和订单金额的大小关系
                        try:
                            total_cost_float = float(total_cost) if total_cost else 0
                        except (ValueError, TypeError):
                            total_cost_float = 0
                        
                        if success_count > 0 and order_id and total_cost_float > 0:
                            try:
                                # 获取订单详情信息（数量、金额、规格等）
                                cost_check_order_detail_info = None
                                try:
                                    # 先尝试使用步骤1中已获取的订单详情
                                    if order_detail_result:
                                        cost_check_order_detail_info = order_detail_result
                                        logger.info(f"[{msg_time}] 【成本检查】使用步骤1已获取的订单详情")
                                    else:
                                        # 从数据库查找现有订单信息
                                        existing_order = db_manager.get_order_by_id_enhanced(order_id)
                                        if existing_order and existing_order.get('amount'):
                                            cost_check_order_detail_info = existing_order
                                            logger.info(f"[{msg_time}] 【成本检查】从数据库获取订单信息")
                                        else:
                                            # 如果都没有，重新获取订单详情
                                            cost_check_order_detail_info = await self.fetch_order_detail_info(order_id, item_id, send_user_id)
                                            logger.info(f"[{msg_time}] 【成本检查】重新获取订单详情信息")
                                except Exception as detail_e:
                                    logger.warning(f"[{msg_time}] 【成本检查】获取订单详情失败: {self._safe_str(detail_e)}")
                                
                                # 如果获取到了订单详情，检查成本和订单金额的大小关系
                                if cost_check_order_detail_info and cost_check_order_detail_info.get('amount'):
                                    try:
                                        # 确保 order_amount 是数字类型
                                        order_amount_raw = cost_check_order_detail_info['amount']
                                        order_amount = float(order_amount_raw)
                                        
                                        logger.info(f"[{msg_time}] 【成本检查】订单金额: {order_amount}, 卡券成本: {total_cost_float}")
                                        
                                        if total_cost_float > order_amount:
                                            logger.warning(f"[{msg_time}] 【成本检查】⚠️ 订单金额({order_amount})小于卡券成本({total_cost_float})，发送通知")
                                            
                                            # 构建通知消息
                                            notification_msg = f"🚨 成本预警通知\n\n" \
                                                             f"订单ID: {order_id}\n" \
                                                             f"商品ID: {item_id}\n" \
                                                             f"买家: {send_user_name}({send_user_id})\n" \
                                                             f"订单金额: ¥{order_amount:.2f}\n" \
                                                             f"卡券成本: ¥{total_cost_float:.2f}\n" \
                                                             f"亏损金额: ¥{total_cost_float - order_amount:.2f}\n" \
                                                             f"发送时间: {msg_time}"
                                            
                                            # 发送通知
                                            await self.send_notification(
                                                send_user_name="系统",
                                                send_user_id="system",
                                                send_message=notification_msg,
                                                item_id=item_id
                                            )
                                            logger.info(f"[{msg_time}] 【成本检查】✅ 成本预警通知已发送")
                                        else:
                                            logger.info(f"[{msg_time}] 【成本检查】✅ 订单金额({order_amount:.2f})大于等于卡券成本({total_cost_float:.2f})，无需通知")
                                    except (ValueError, TypeError) as parse_e:
                                        logger.error(f"[{msg_time}] 【成本检查】数据类型转换错误 - 订单金额: {cost_check_order_detail_info.get('amount')} (类型: {type(cost_check_order_detail_info.get('amount'))}), 卡券成本: {total_cost_float} (类型: {type(total_cost_float)}), 错误: {self._safe_str(parse_e)}")
                                else:
                                    logger.warning(f"[{msg_time}] 【成本检查】未获取到订单金额信息，无法进行成本检查")
                            except Exception as cost_check_e:
                                logger.error(f"[{msg_time}] 【成本检查】成本检查异常: {self._safe_str(cost_check_e)}")
                        
                        logger.info(f"[{msg_time}] 【JH API发送完成】成功: {success_count}, 失败: {failed_count}")
                        return  # JH API卡券处理完成，直接返回
                    else:
                        logger.error(f"[{msg_time}] 【步骤4】❌ JH API未返回卡券或返回空列表")
                        return
                
                # 步骤4: 按照实际数量发送卡券（非API类型）
                logger.info(f"[{msg_time}] 【步骤4】开始发送 {actual_send_quantity} 个卡券")
                
                # 标记已发货（防重复）- 基于订单ID
                self.mark_delivery_sent(order_id)

                # 多次发送卡券
                success_count = 0
                failed_count = 0
                consumed_coupon_codes = []  # 记录所有消费的券码
                card_description_to_send = None  # 记录需要发送的备注信息
                actual_data_list = []  # 记录所有实际数据，用于备注变量替换

                for i in range(actual_send_quantity):
                    try:
                        logger.info(f"[{msg_time}] 【步骤4】发送第 {i+1}/{actual_send_quantity} 个卡券")
                        
                        # 直接获取单个卡券内容（避免重复的商品信息保存等操作）
                        current_delivery_result = self._get_single_coupon_content(rule, order_id, item_id)
                        
                        if not current_delivery_result or current_delivery_result == "__NO_STOCK__":
                            logger.warning(f"[{msg_time}] 【步骤4】第 {i+1} 个卡券获取失败，跳过")
                            failed_count += 1
                            continue

                        # 处理不同类型的发货内容
                        delivery_content = current_delivery_result
                        send_success = False
                        card_id_to_consume = None
                        
                        if delivery_content.startswith("__IMAGE_SEND__"):
                            # 传统图片发送标记
                            image_data = delivery_content.replace("__IMAGE_SEND__", "")
                            if "|" in image_data:
                                card_id_str, image_url = image_data.split("|", 1)
                                try:
                                    card_id = int(card_id_str)
                                except ValueError:
                                    logger.error(f"无效的卡券ID: {card_id_str}")
                                    card_id = None
                            else:
                                card_id = None
                                image_url = image_data

                            try:
                                await self.send_image_msg(websocket, chat_id, send_user_id, image_url, card_id=card_id)
                                logger.info(f'[{msg_time}] 【自动发货图片】第 {i+1} 个已向 {user_url} 发送图片: {image_url}')
                                send_success = True
                            except Exception as e:
                                logger.error(f"第 {i+1} 个自动发货图片失败: {self._safe_str(e)}")
                                
                        elif delivery_content.startswith("__BATCH_DATA_IMAGE__"):
                            # 批量数据生成的图片
                            parts = delivery_content.replace("__BATCH_DATA_IMAGE__", "").split("|")
                            if len(parts) >= 3:
                                card_id_str, image_url, actual_data = parts[0], parts[1], parts[2]
                                try:
                                    card_id = int(card_id_str)
                                    card_id_to_consume = card_id
                                except ValueError:
                                    logger.error(f"无效的卡券ID: {card_id_str}")
                                    card_id = None

                                try:
                                    await self.send_image_msg(websocket, chat_id, send_user_id, image_url, card_id=card_id)
                                    logger.info(f'[{msg_time}] 【自动发货图片】第 {i+1} 个已向 {user_url} 发送图片: {image_url}')
                                    send_success = True
                                except Exception as e:
                                    logger.error(f"第 {i+1} 个自动发货图片失败: {self._safe_str(e)}")
                                    # 图片发送失败，发送文本
                                    try:
                                        await self.send_msg(websocket, chat_id, send_user_id, actual_data)
                                        logger.info(f'[{msg_time}] 【自动发货文本】第 {i+1} 个图片失败后发送文本: {actual_data}')
                                        send_success = True
                                    except Exception as text_e:
                                        logger.error(f"第 {i+1} 个发送文本也失败: {self._safe_str(text_e)}")
                                        
                        elif delivery_content.startswith("__BATCH_DATA_IMAGE_WITH_NOTE__"):
                            # 批量数据图片+备注分开发送（备注稍后统一发送）
                            parts = delivery_content.replace("__BATCH_DATA_IMAGE_WITH_NOTE__", "").split("|")
                            if len(parts) >= 4:
                                card_id_str, image_url, actual_data, card_description = parts[0], parts[1], parts[2], parts[3]
                                try:
                                    card_id = int(card_id_str)
                                    card_id_to_consume = card_id
                                except ValueError:
                                    logger.error(f"无效的卡券ID: {card_id_str}")
                                    card_id = None

                                # 记录备注信息（只记录一次）
                                if card_description and card_description.strip() and not card_description_to_send:
                                    card_description_to_send = card_description
                                
                                # 记录实际数据用于备注变量替换和券码记录
                                if actual_data:
                                    actual_data_list.append(actual_data)

                                try:
                                    # 只发送图片，不发送备注
                                    await self.send_image_msg(websocket, chat_id, send_user_id, image_url, card_id=card_id)
                                    logger.info(f'[{msg_time}] 【自动发货图片】第 {i+1} 个已向 {user_url} 发送图片: {image_url}')
                                    send_success = True
                                except Exception as e:
                                    logger.error(f"第 {i+1} 个自动发货图片失败: {self._safe_str(e)}")
                                    # 图片发送失败，发送文本
                                    try:
                                        await self.send_msg(websocket, chat_id, send_user_id, actual_data)
                                        logger.info(f'[{msg_time}] 【自动发货文本】第 {i+1} 个图片失败后发送文本: {actual_data}')
                                        send_success = True
                                    except Exception as text_e:
                                        logger.error(f"第 {i+1} 个发送文本也失败: {self._safe_str(text_e)}")
                            else:
                                logger.error(f"第 {i+1} 个批量数据图片+备注格式错误: {delivery_content}")
                                

                        elif delivery_content.startswith("__BATCH_DATA__"):
                            # 批量数据文本
                            parts = delivery_content.replace("__BATCH_DATA__", "").split("|", 1)
                            if len(parts) == 2:
                                card_id_str, actual_data = parts
                                try:
                                    card_id_to_consume = int(card_id_str)
                                except ValueError:
                                    logger.error(f"无效的卡券ID: {card_id_str}")

                                try:
                                    await self.send_msg(websocket, chat_id, send_user_id, actual_data)
                                    logger.info(f'[{msg_time}] 【自动发货文本】第 {i+1} 个已向 {user_url} 发送: {actual_data}')
                                    send_success = True
                                except Exception as e:
                                    logger.error(f"第 {i+1} 个自动发货文本失败: {self._safe_str(e)}")
                        else:
                            # 普通文本发货内容
                            try:
                                await self.send_msg(websocket, chat_id, send_user_id, delivery_content)
                                logger.info(f'[{msg_time}] 【自动发货】第 {i+1} 个已向 {user_url} 发送发货内容')
                                send_success = True
                            except Exception as e:
                                logger.error(f"第 {i+1} 个自动发货文本失败: {self._safe_str(e)}")
                        
                        # 只有在发送成功后才消费卡券
                        if send_success and card_id_to_consume:
                            try:
                                consumed_data = db_manager.consume_batch_data(card_id_to_consume)
                                if consumed_data:
                                    consumed_coupon_codes.append(consumed_data)  # 记录消费的券码
                                    logger.info(f"第 {i+1} 个发送成功后消费卡券: 卡券ID={card_id_to_consume}, 消费内容={consumed_data}")
                                else:
                                    logger.warning(f"第 {i+1} 个卡券消费失败: 卡券ID={card_id_to_consume}")
                            except Exception as e:
                                logger.error(f"第 {i+1} 个消费卡券异常: {self._safe_str(e)}")
                        elif send_success:
                            # 对于__BATCH_DATA_IMAGE_WITH_NOTE__类型，券码信息已在actual_data_list中
                            # 将其添加到consumed_coupon_codes以确保订单更新时有券码信息
                            if delivery_content.startswith("__BATCH_DATA_IMAGE_WITH_NOTE__"):
                                parts = delivery_content.replace("__BATCH_DATA_IMAGE_WITH_NOTE__", "").split("|")
                                if len(parts) >= 3:
                                    actual_data = parts[2]
                                    if actual_data and actual_data not in consumed_coupon_codes:
                                        consumed_coupon_codes.append(actual_data)
                                        logger.info(f"第 {i+1} 个记录图片+备注类型券码: {actual_data}")
                        
                        if send_success:
                            success_count += 1
                        else:
                            failed_count += 1
                            
                        # 在发送多个卡券时添加间隔，避免发送过快
                        if i < actual_send_quantity - 1:  # 不是最后一个
                            await asyncio.sleep(0.5)  # 500ms间隔
                            
                    except Exception as e:
                        logger.error(f"第 {i+1} 个卡券发送过程异常: {self._safe_str(e)}")
                        failed_count += 1

                # 发送结果汇总
                logger.info(f"[{msg_time}] 【步骤4】发送完成 - 成功: {success_count}, 失败: {failed_count}, 总计: {actual_send_quantity}")
                
                # 如果有成功发送的卡券，扣除自动发货费用（10聚合豆）
                if success_count > 0:
                    try:
                        # 获取用户ID
                        user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
                        if user_id:
                            # 检查余额并扣费（自动发货成功扣除10聚合豆）
                            balance_sufficient = db_manager.check_and_consume_balance(
                                user_id=user_id,
                                amount=10.0,
                                description=f"自动发货 - 商品ID:{item_id}, 规则ID:{rule['id']}",
                                order_id=order_id
                            )
                            
                            if balance_sufficient:
                                logger.info(f"[{msg_time}] 【自动发货扣费】成功扣除10聚合豆，用户ID:{user_id}")
                                # 增加发货次数统计
                                db_manager.increment_delivery_times(rule['id'])
                            else:
                                logger.warning(f"[{msg_time}] 【自动发货扣费】用户余额不足，无法扣除10聚合豆")
                        else:
                            logger.error(f"[{msg_time}] 【自动发货扣费】无法获取用户ID，跳过扣费")
                    except Exception as e:
                        logger.error(f"[{msg_time}] 【自动发货扣费】扣费过程异常: {self._safe_str(e)}")
                
                # 发送完所有卡券后，统一发送一次备注信息
                if success_count > 0 and card_description_to_send:
                    try:
                        # 添加短暂延迟，确保卡券和备注消息分开显示
                        await asyncio.sleep(1)
                        
                        # 处理备注中的变量替换
                        if '{DELIVERY_CONTENT}' in card_description_to_send:
                            # 如果备注中包含变量，使用所有实际数据的组合
                            combined_data = "; ".join(actual_data_list) if actual_data_list else ""
                            processed_description = card_description_to_send.replace('{DELIVERY_CONTENT}', combined_data)
                        else:
                            processed_description = card_description_to_send
                        
                        await self.send_msg(websocket, chat_id, send_user_id, processed_description)
                        logger.info(f'[{msg_time}] 【自动发货备注】已向 {user_url} 发送统一备注: {processed_description}')
                    except Exception as e:
                        logger.error(f"发送统一备注失败: {self._safe_str(e)}")
                
                # 如果有成功发送的卡券，更新订单状态为"已发货"
                if success_count > 0 and order_id:
                    try:
                        from datetime import datetime
                        
                        # 获取订单详情信息（数量、金额、规格等）
                        order_detail_info = None
                        try:
                            # 先尝试使用步骤1中已获取的订单详情
                            if order_detail_result:
                                order_detail_info = order_detail_result
                                logger.info(f"[{msg_time}] 【普通发货订单】使用步骤1已获取的订单详情")
                            else:
                                # 从数据库查找现有订单信息
                                existing_order = db_manager.get_order_by_id_enhanced(order_id)
                                if existing_order and (existing_order.get('quantity') or existing_order.get('amount')):
                                    order_detail_info = existing_order
                                    logger.info(f"[{msg_time}] 【普通发货订单】从数据库获取订单信息")
                                else:
                                    # 如果都没有，重新获取订单详情
                                    order_detail_info = await self.fetch_order_detail_info(order_id, item_id, send_user_id)
                                    logger.info(f"[{msg_time}] 【普通发货订单】重新获取订单详情信息")
                        except Exception as detail_e:
                            logger.warning(f"[{msg_time}] 【普通发货订单】获取订单详情失败: {self._safe_str(detail_e)}")
                        
                        # 更新订单状态为已发货，并记录券码信息
                        coupon_codes_str = "; ".join(consumed_coupon_codes) if consumed_coupon_codes else None
                        order_data = {
                            'order_id': order_id,
                            'buyer_id': send_user_id,
                            'buyer_name': send_user_name,  # 添加买家名称
                            'item_id': item_id,
                            'order_status': '已发货',
                            'shipping_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                            'coupon_code': coupon_codes_str,  # 记录所有券码信息
                            'raw_message': f"自动发货成功更新状态 - 发送{success_count}个卡券 - {msg_time}"
                        }
                        
                        # 如果获取到了订单详情，添加数量和金额信息
                        if order_detail_info:
                            if order_detail_info.get('quantity'):
                                order_data['quantity'] = order_detail_info['quantity']
                                logger.info(f"[{msg_time}] 【普通发货订单】添加数量信息: {order_detail_info['quantity']}")
                            
                            if order_detail_info.get('amount'):
                                order_data['amount'] = order_detail_info['amount']
                                logger.info(f"[{msg_time}] 【普通发货订单】添加金额信息: {order_detail_info['amount']}")
                            
                            # 添加规格信息
                            if order_detail_info.get('spec_name'):
                                order_data['spec_name'] = order_detail_info['spec_name']
                            if order_detail_info.get('spec_value'):
                                order_data['spec_value'] = order_detail_info['spec_value']
                        
                        success = db_manager.save_order(self.cookie_id, order_data)
                        if success:
                            logger.info(f"[{msg_time}] 【订单状态更新】订单 {order_id} 状态已更新为: 已发货, 发送数量: {success_count}, 券码: {coupon_codes_str}")
                            
                            # 检查是否启用自动确认发货
                            if self.is_auto_confirm_enabled():
                                try:
                                    # 检查确认发货冷却时间
                                    current_time = time.time()
                                    should_confirm = True

                                    if order_id in self.confirmed_orders:
                                        last_confirm_time = self.confirmed_orders[order_id]
                                        if current_time - last_confirm_time < self.order_confirm_cooldown:
                                            logger.info(f"[{msg_time}] 【自动确认发货】订单 {order_id} 已在 {self.order_confirm_cooldown} 秒内确认过，跳过重复确认")
                                            should_confirm = False

                                    if should_confirm:
                                        logger.info(f"[{msg_time}] 【自动确认发货】开始确认发货: 订单ID={order_id}")
                                        confirm_result = await self.auto_confirm(order_id, item_id)
                                        if confirm_result.get('success'):
                                            self.confirmed_orders[order_id] = current_time
                                            logger.info(f"[{msg_time}] 🎉 【自动确认发货】确认发货成功！订单ID: {order_id}")
                                        else:
                                            logger.warning(f"[{msg_time}] ⚠️ 【自动确认发货】确认发货失败: {confirm_result.get('error', '未知错误')}")
                                except Exception as confirm_e:
                                    logger.error(f"[{msg_time}] 【自动确认发货】确认发货异常: {self._safe_str(confirm_e)}")
                            else:
                                logger.info(f"[{msg_time}] 【自动确认发货】自动确认发货已关闭，跳过订单 {order_id}")
                            
                            # 只有在订单详情不完整时才异步获取订单详情（避免重复获取）
                            if order_detail_result is None or not order_detail_result.get('quantity'):
                                try:
                                    logger.info(f"[{msg_time}] 【订单详情】开始获取订单 {order_id} 的详细信息")
                                    asyncio.create_task(self.fetch_order_detail_info(
                                        order_id=order_id,
                                        item_id=item_id,
                                        buyer_id=send_user_id,
                                        debug_headless=None
                                    ))
                                except Exception as detail_e:
                                    logger.error(f"[{msg_time}] 【订单详情】异步获取订单详情失败: {self._safe_str(detail_e)}")
                            else:
                                logger.info(f"[{msg_time}] 【订单详情】订单详情已获取，跳过重复获取: {order_id}")
                        else:
                            logger.error(f"[{msg_time}] 【订单状态更新】更新订单状态失败: {order_id}")
                    except Exception as e:
                        logger.error(f"[{msg_time}] 【订单状态更新】更新订单状态异常: {self._safe_str(e)}")

                # 如果有失败的发送，发送通知
                if failed_count > 0:
                    await self.send_delivery_failure_notification(send_user_name, send_user_id, item_id, f"部分发送失败({failed_count}个)")

            except Exception as e:
                logger.error(f"[{msg_time}] 【自动发货】处理异常: {self._safe_str(e)}")
                await self.send_delivery_failure_notification(send_user_name, send_user_id, item_id, "处理异常")
            finally:
                # 清理处理标记
                if order_id:
                    self.unmark_delivery_processing(order_id)

        except Exception as e:
            logger.error(f'[{msg_time}] 【{self.cookie_id}】自动发货处理失败: {self._safe_str(e)}')
            # 清理处理标记
            if 'order_id' in locals() and order_id:
                self.unmark_delivery_processing(order_id)

    async def refresh_token(self, skip_restart=False):
        """刷新token
        
        Args:
            skip_restart: 是否跳过实例重启，用于初始化时避免无限循环
        """
        try:
            logger.info(f"【{self.cookie_id}】开始刷新token...")
            params = {
                'jsv': '2.7.2',
                'appKey': '34839810',
                't': str(int(time.time()) * 1000),
                'sign': '',
                'v': '1.0',
                'type': 'originaljson',
                'accountSite': 'xianyu',
                'dataType': 'json',
                'timeout': '20000',
                'api': 'mtop.taobao.idlemessage.pc.login.token',
                'sessionOption': 'AutoLoginOnly',
                'spm_cnt': 'a21ybx.im.0.0',
            }
            data_val = '{"appKey":"444e9908a51d1cb236a27862abc769c9","deviceId":"' + self.device_id + '"}'
            data = {
                'data': data_val,
            }
            
            # 获取token
            token = None
            token = trans_cookies(self.cookies_str).get('_m_h5_tk', '').split('_')[0] if trans_cookies(self.cookies_str).get('_m_h5_tk') else ''
            
            # 检查Token状态，如果之前是失效状态，重置为有效状态
            from db_manager import db_manager
            current_token_status = db_manager.get_token_status(self.cookie_id)
            if current_token_status == 'invalid':
                logger.info(f"【{self.cookie_id}】检测到Cookie更新，重置Token状态为有效")
                db_manager.update_token_status(self.cookie_id, 'valid')
            
            sign = generate_sign(params['t'], token, data_val)
            params['sign'] = sign
            
            # 发送请求
            headers = DEFAULT_HEADERS.copy()
            headers['cookie'] = self.cookies_str
            
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    API_ENDPOINTS.get('token'),
                    params=params,
                    data=data,
                    headers=headers
                ) as response:
                    res_json = await response.json()
                    
                    # 注释掉的自动更新Cookie逻辑 - 已禁用
                    # if 'set-cookie' in response.headers:
                    #     new_cookies = {}
                    #     for cookie in response.headers.getall('set-cookie', []):
                    #         if '=' in cookie:
                    #             name, value = cookie.split(';')[0].split('=', 1)
                    #             new_cookies[name.strip()] = value.strip()
                    #     
                    #     # 更新cookies
                    #     if new_cookies:
                    #         self.cookies.update(new_cookies)
                    #         # 生成新的cookie字符串
                    #         self.cookies_str = '; '.join([f"{k}={v}" for k, v in self.cookies.items()])
                    #         # 更新数据库中的Cookie
                    #         await self.update_config_cookies()
                    #         logger.debug("已更新Cookie到数据库")
                    
                    if isinstance(res_json, dict):
                        ret_value = res_json.get('ret', [])
                        # 检查ret是否包含成功信息
                        if any('SUCCESS::调用成功' in ret for ret in ret_value):
                            if 'data' in res_json and 'accessToken' in res_json['data']:
                                new_token = res_json['data']['accessToken']
                                self.current_token = new_token
                                
                                # 更新Token状态为有效
                                from db_manager import db_manager
                                db_manager.update_token_status(self.cookie_id, 'valid')
                                logger.info(f"【{self.cookie_id}】Token状态已更新为有效")
                                
                                logger.info(f"【{self.cookie_id}】Token刷新成功")
                                # 只有在不跳过重启时才调用实例重启方法
                                if not skip_restart:
                                    await self._restart_instance()
                                else:
                                    logger.info(f"【{self.cookie_id}】跳过实例重启（初始化模式）")
                                return new_token
                            
                    logger.error(f"【{self.cookie_id}】Token刷新失败: {res_json}")

                    # 只有在确实是Token相关错误时才更新Token状态为失效
                    error_str = str(res_json)
                    if any(keyword in error_str for keyword in ['TOKEN', 'token', '令牌', 'EXPIRED', 'expired', '过期']):
                        from db_manager import db_manager
                        import datetime
                        current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                        db_manager.update_token_status(self.cookie_id, 'invalid', current_time)
                        logger.warning(f"【{self.cookie_id}】检测到Token相关错误，已更新Token状态为失效")
                        # 注意：自动续期功能已移除，需要手动更新Cookie
                    else:
                        logger.info(f"【{self.cookie_id}】Token刷新失败但非Token错误，保持当前状态")
                    
                    # 发送Token刷新失败通知
                    await self.send_token_refresh_notification(f"Token刷新失败: {res_json}", "token_refresh_failed")
                    return None

        except Exception as e:
            logger.error(f"Token刷新异常: {self._safe_str(e)}")

            # 只有在确实是Token相关异常时才更新Token状态为失效
            error_str = str(e)
            if any(keyword in error_str for keyword in ['TOKEN', 'token', '令牌', 'EXPIRED', 'expired', '过期', 'UNAUTHORIZED', 'unauthorized', '401']):
                from db_manager import db_manager
                import datetime
                current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                db_manager.update_token_status(self.cookie_id, 'invalid', current_time)
                logger.warning(f"【{self.cookie_id}】检测到Token相关异常，已更新Token状态为失效")
                # 注意：自动续期功能已移除，需要手动更新Cookie
            else:
                logger.info(f"【{self.cookie_id}】Token刷新异常但非Token错误，保持当前状态")
            
            # 发送Token刷新异常通知
            await self.send_token_refresh_notification(f"Token刷新异常: {str(e)}", "token_refresh_exception")
            return None

    async def _handle_token_expired(self):
        """处理Token失效事件（已弃用自动续期功能）"""
        logger.info(f"【{self.cookie_id}】检测到Token失效，但自动续期功能已移除，请手动更新Cookie")
        
        # 将Token状态标记为失效
        try:
            from db_manager import db_manager
            db_manager.update_token_status(self.cookie_id, 'invalid')
        except Exception as e:
            logger.error(f"【{self.cookie_id}】更新Token状态失败: {self._safe_str(e)}")
        
        # 发送Token失效通知
        await self.send_token_refresh_notification(
            f"账号 {self.cookie_id} Token已失效，自动续期功能已移除，请手动更新Cookie", 
            "token_expired"
        )
        
        return False



    def enable_cookie_refresh(self, enabled: bool = True):
        """启用或禁用Cookie刷新功能（已弃用，仅保留接口兼容性）"""
        # 注意：Cookie自动刷新功能已完全移除，此方法仅保留兼容性
        logger.info(f"【{self.cookie_id}】Cookie自动续期功能已完全移除，此调用无效果")

    async def _restart_instance(self):
        """重启XianyuLive实例"""
        try:
            logger.info(f"【{self.cookie_id}】Token刷新成功，准备重启实例...")

            # 导入CookieManager
            from cookie_manager import manager as cookie_manager

            if cookie_manager:
                # 通过CookieManager重启实例
                logger.info(f"【{self.cookie_id}】通过CookieManager重启实例...")

                # 使用异步方式调用update_cookie，避免阻塞
                def restart_task():
                    try:
                        cookie_manager.update_cookie(self.cookie_id, self.cookies_str)
                        logger.info(f"【{self.cookie_id}】实例重启请求已发送")
                    except Exception as e:
                        logger.error(f"【{self.cookie_id}】重启实例失败: {e}")

                # 在后台执行重启任务
                import threading
                restart_thread = threading.Thread(target=restart_task, daemon=True)
                restart_thread.start()

                logger.info(f"【{self.cookie_id}】实例重启已在后台执行")
            else:
                logger.warning(f"【{self.cookie_id}】CookieManager不可用，无法重启实例")

        except Exception as e:
            logger.error(f"【{self.cookie_id}】重启实例失败: {self._safe_str(e)}")
            # 发送重启失败通知
            await self.send_token_refresh_notification(f"实例重启失败: {str(e)}", "instance_restart_failed")

    async def update_config_cookies(self):
        """更新数据库中的cookies（已禁用，仅保留接口兼容性）"""
        # 注意：自动更新Cookie功能已完全移除，此方法仅保留兼容性
        logger.debug(f"【{self.cookie_id}】update_config_cookies调用被忽略，自动更新Cookie功能已移除")
        
        # 注释掉的自动更新Cookie逻辑 - 已禁用
        # try:
        #     from db_manager import db_manager
        # 
        #     # 更新数据库中的Cookie
        #     if hasattr(self, 'cookie_id') and self.cookie_id:
        #         try:
        #             # 获取当前Cookie的用户ID，避免在刷新时改变所有者
        #             current_user_id = None
        #             if hasattr(self, 'user_id') and self.user_id:
        #                 current_user_id = self.user_id
        # 
        #             db_manager.save_cookie(self.cookie_id, self.cookies_str, current_user_id)
        #             logger.debug(f"已更新Cookie到数据库: {self.cookie_id}")
        #         except Exception as e:
        #             logger.error(f"更新数据库Cookie失败: {self._safe_str(e)}")
        #             # 发送数据库更新失败通知
        #             await self.send_token_refresh_notification(f"数据库Cookie更新失败: {str(e)}", "db_update_failed")
        #     else:
        #         logger.warning("Cookie ID不存在，无法更新数据库")
        #         # 发送Cookie ID缺失通知
        #         await self.send_token_refresh_notification("Cookie ID不存在，无法更新数据库", "cookie_id_missing")
        # 
        # except Exception as e:
        #     logger.error(f"更新Cookie失败: {self._safe_str(e)}")
        #     # 发送Cookie更新失败通知
        #     await self.send_token_refresh_notification(f"Cookie更新失败: {str(e)}", "cookie_update_failed")

    async def save_item_info_to_db(self, item_id: str, item_detail: str = None, item_title: str = None):
        """保存商品信息到数据库

        Args:
            item_id: 商品ID
            item_detail: 商品详情内容（可以是任意格式的文本）
            item_title: 商品标题
        """
        try:
            # 跳过以 auto_ 开头的商品ID
            if item_id and item_id.startswith('auto_'):
                logger.debug(f"跳过保存自动生成的商品ID: {item_id}")
                return

            # 验证：如果只有商品ID，没有商品标题和商品详情，则不插入数据库
            if not item_title and not item_detail:
                logger.debug(f"跳过保存商品信息：缺少商品标题和详情 - {item_id}")
                return

            # 如果有商品标题但没有详情，也跳过（根据需求，需要同时有标题和详情）
            if not item_title or not item_detail:
                logger.debug(f"跳过保存商品信息：商品标题或详情不完整 - {item_id}")
                return

            from db_manager import db_manager

            # 直接使用传入的详情内容
            item_data = item_detail

            # 保存到数据库
            success = db_manager.save_item_info(self.cookie_id, item_id, item_data)
            if success:
                logger.info(f"商品信息已保存到数据库: {item_id}")
            else:
                logger.warning(f"保存商品信息到数据库失败: {item_id}")

        except Exception as e:
            logger.error(f"保存商品信息到数据库异常: {self._safe_str(e)}")

    async def save_item_detail_only(self, item_id, item_detail):
        """仅保存商品详情（不影响标题等基本信息）"""
        try:
            from db_manager import db_manager

            # 使用专门的详情更新方法
            success = db_manager.update_item_detail(self.cookie_id, item_id, item_detail)

            if success:
                logger.info(f"商品详情已更新: {item_id}")
            else:
                logger.warning(f"更新商品详情失败: {item_id}")

            return success

        except Exception as e:
            logger.error(f"更新商品详情异常: {self._safe_str(e)}")
            return False

    async def fetch_item_detail_from_api(self, item_id: str) -> str:
        """从外部API获取商品详情

        Args:
            item_id: 商品ID

        Returns:
            str: 商品详情文本，获取失败返回空字符串
        """
        try:
            # 检查是否启用自动获取功能
            from config import config
            auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})

            if not auto_fetch_config.get('enabled', True):
                logger.debug(f"自动获取商品详情功能已禁用: {item_id}")
                return ""

            # 从配置获取API地址和超时时间
            api_base_url = auto_fetch_config.get('api_url', 'https://selfapi.zhinianboke.com/api/getItemDetail')
            timeout_seconds = auto_fetch_config.get('timeout', 10)

            api_url = f"{api_base_url}/{item_id}"

            logger.info(f"正在从外部API获取商品详情: {item_id}")

            # 使用aiohttp发送异步请求
            import aiohttp
            import asyncio

            timeout = aiohttp.ClientTimeout(total=timeout_seconds)

            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(api_url) as response:
                    if response.status == 200:
                        result = await response.json()

                        # 检查返回状态
                        if result.get('status') == '200' and result.get('data'):
                            item_detail = result['data']
                            logger.info(f"成功获取商品详情: {item_id}, 长度: {len(item_detail)}")
                            logger.debug(f"商品详情内容: {item_detail[:200]}...")
                            return item_detail
                        else:
                            logger.warning(f"API返回状态异常: {result.get('status')}, message: {result.get('message')}")
                            return ""
                    else:
                        logger.warning(f"API请求失败: HTTP {response.status}")
                        return ""

        except asyncio.TimeoutError:
            logger.warning(f"获取商品详情超时: {item_id}")
            return ""
        except Exception as e:
            logger.error(f"获取商品详情异常: {item_id}, 错误: {self._safe_str(e)}")
            return ""

    async def save_items_list_to_db(self, items_list):
        """批量保存商品列表信息到数据库（并发安全）

        Args:
            items_list: 从get_item_list_info获取的商品列表
        """
        try:
            from db_manager import db_manager

            # 准备批量数据
            batch_data = []
            items_need_detail = []  # 需要获取详情的商品列表

            for item in items_list:
                item_id = item.get('id')
                if not item_id or item_id.startswith('auto_'):
                    continue

                # 构造商品详情数据
                item_detail = {
                    'title': item.get('title', ''),
                    'price': item.get('price', ''),
                    'price_text': item.get('price_text', ''),
                    'category_id': item.get('category_id', ''),
                    'auction_type': item.get('auction_type', ''),
                    'item_status': item.get('item_status', 0),
                    'detail_url': item.get('detail_url', ''),
                    'pic_info': item.get('pic_info', {}),
                    'detail_params': item.get('detail_params', {}),
                    'track_params': item.get('track_params', {}),
                    'item_label_data': item.get('item_label_data', {}),
                    'card_type': item.get('card_type', 0)
                }

                # 检查数据库中是否已有详情
                existing_item = db_manager.get_item_info(self.cookie_id, item_id)
                has_detail = existing_item and existing_item.get('item_detail') and existing_item['item_detail'].strip()

                batch_data.append({
                    'cookie_id': self.cookie_id,
                    'item_id': item_id,
                    'item_title': item.get('title', ''),
                    'item_description': '',  # 暂时为空
                    'item_category': str(item.get('category_id', '')),
                    'item_price': item.get('price_text', ''),
                    'item_detail': json.dumps(item_detail, ensure_ascii=False)
                })

                # 如果没有详情，添加到需要获取详情的列表
                if not has_detail:
                    items_need_detail.append({
                        'item_id': item_id,
                        'item_title': item.get('title', '')
                    })

            if not batch_data:
                logger.info("没有有效的商品数据需要保存")
                return 0

            # 使用批量保存方法（并发安全）
            saved_count = db_manager.batch_save_item_basic_info(batch_data)
            logger.info(f"批量保存商品信息完成: {saved_count}/{len(batch_data)} 个商品")

            # 异步获取缺失的商品详情
            if items_need_detail:
                from config import config
                auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})

                if auto_fetch_config.get('enabled', True):
                    logger.info(f"发现 {len(items_need_detail)} 个商品缺少详情，开始获取...")
                    detail_success_count = await self._fetch_missing_item_details(items_need_detail)
                    logger.info(f"成功获取 {detail_success_count}/{len(items_need_detail)} 个商品的详情")
                else:
                    logger.info(f"发现 {len(items_need_detail)} 个商品缺少详情，但自动获取功能已禁用")

            return saved_count

        except Exception as e:
            logger.error(f"批量保存商品信息异常: {self._safe_str(e)}")
            return 0

    async def _fetch_missing_item_details(self, items_need_detail):
        """批量获取缺失的商品详情

        Args:
            items_need_detail: 需要获取详情的商品列表

        Returns:
            int: 成功获取详情的商品数量
        """
        success_count = 0

        try:
            from db_manager import db_manager
            from config import config

            # 从配置获取并发数量和延迟时间
            auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})
            max_concurrent = auto_fetch_config.get('max_concurrent', 3)
            retry_delay = auto_fetch_config.get('retry_delay', 0.5)

            # 限制并发数量，避免对API服务器造成压力
            semaphore = asyncio.Semaphore(max_concurrent)

            async def fetch_single_item_detail(item_info):
                async with semaphore:
                    try:
                        item_id = item_info['item_id']
                        item_title = item_info['item_title']

                        # 获取商品详情
                        item_detail_text = await self.fetch_item_detail_from_api(item_id)

                        if item_detail_text:
                            # 保存详情到数据库
                            success = await self.save_item_detail_only(item_id, item_detail_text)
                            if success:
                                logger.info(f"✅ 成功获取并保存商品详情: {item_id} - {item_title}")
                                return 1
                            else:
                                logger.warning(f"❌ 获取详情成功但保存失败: {item_id}")
                        else:
                            logger.warning(f"❌ 未能获取商品详情: {item_id} - {item_title}")

                        # 添加延迟，避免请求过于频繁
                        await asyncio.sleep(retry_delay)
                        return 0

                    except Exception as e:
                        logger.error(f"获取单个商品详情异常: {item_info.get('item_id', 'unknown')}, 错误: {self._safe_str(e)}")
                        return 0

            # 并发获取所有商品详情
            tasks = [fetch_single_item_detail(item_info) for item_info in items_need_detail]
            results = await asyncio.gather(*tasks, return_exceptions=True)

            # 统计成功数量
            for result in results:
                if isinstance(result, int):
                    success_count += result
                elif isinstance(result, Exception):
                    logger.error(f"获取商品详情任务异常: {result}")

            return success_count

        except Exception as e:
            logger.error(f"批量获取商品详情异常: {self._safe_str(e)}")
            return success_count

    async def get_item_info(self, item_id, retry_count=0):
        """获取商品信息，自动处理token失效的情况"""
        if retry_count >= 4:  # 最多重试3次
            logger.error("获取商品信息失败，重试次数过多")
            return {"error": "获取商品信息失败，重试次数过多"}

        # Token刷新功能已禁用
        # 如果是重试（retry_count > 0），强制刷新token
        if retry_count > 0:
            logger.info(f"重试第{retry_count}次，但Token刷新功能已禁用，使用现有Token")
        else:
            # 使用现有的token，不再自动刷新
            logger.debug(f"使用现有Token，自动刷新功能已禁用")

        # 确保session已创建
        if not self.session:
            await self.create_session()

        params = {
            'jsv': '2.7.2',
            'appKey': '34839810',
            't': str(int(time.time()) * 1000),
            'sign': '',
            'v': '1.0',
            'type': 'originaljson',
            'accountSite': 'xianyu',
            'dataType': 'json',
            'timeout': '20000',
            'api': 'mtop.taobao.idle.pc.detail',
            'sessionOption': 'AutoLoginOnly',
            'spm_cnt': 'a21ybx.im.0.0',
        }

        data_val = '{"itemId":"' + item_id + '"}'
        data = {
            'data': data_val,
        }

        # 始终从最新的cookies中获取_m_h5_tk token（刷新后cookies会被更新）
        token = trans_cookies(self.cookies_str).get('_m_h5_tk', '').split('_')[0] if trans_cookies(self.cookies_str).get('_m_h5_tk') else ''

        logger.warning(111)
        logger.warning(token)
        if token:
            logger.debug(f"使用cookies中的_m_h5_tk token: {token}")
        else:
            logger.warning("cookies中没有找到_m_h5_tk token")

        from utils.xianyu_utils import generate_sign
        sign = generate_sign(params['t'], token, data_val)
        params['sign'] = sign

        try:
            async with self.session.post(
                'https://h5api.m.goofish.com/h5/mtop.taobao.idle.pc.detail/1.0/',
                params=params,
                data=data
            ) as response:
                res_json = await response.json()

                # 注释掉的自动更新Cookie逻辑 - 已禁用
                # if 'set-cookie' in response.headers:
                #     new_cookies = {}
                #     for cookie in response.headers.getall('set-cookie', []):
                #         if '=' in cookie:
                #             name, value = cookie.split(';')[0].split('=', 1)
                #             new_cookies[name.strip()] = value.strip()
                #     
                #     # 更新cookies
                #     if new_cookies:
                #         self.cookies.update(new_cookies)
                #         # 生成新的cookie字符串
                #         self.cookies_str = '; '.join([f"{k}={v}" for k, v in self.cookies.items()])
                #         # 更新数据库中的Cookie
                #         await self.update_config_cookies()
                #         logger.debug("已更新Cookie到数据库")

                logger.debug(f"商品信息获取成功: {res_json}")
                # 检查返回状态
                if isinstance(res_json, dict):
                    ret_value = res_json.get('ret', [])
                    # 检查ret是否包含成功信息
                    if not any('SUCCESS::调用成功' in ret for ret in ret_value):
                        logger.warning(f"商品信息API调用失败，错误信息: {ret_value}")
                        
                        # 检查是否是Token失效相关错误
                        error_str = str(ret_value)
                        if any(keyword in error_str for keyword in ['TOKEN', 'token', '令牌', 'EXPIRED', 'expired', '过期']):
                            logger.warning(f"【{self.cookie_id}】商品信息API检测到Token失效，自动续期功能已移除，需要手动更新Cookie")
                        
                        await asyncio.sleep(0.5)
                        return await self.get_item_info(item_id, retry_count + 1)
                    else:
                        logger.debug(f"商品信息获取成功: {item_id}")
                        return res_json
                else:
                    logger.error(f"商品信息API返回格式异常: {res_json}")
                    return await self.get_item_info(item_id, retry_count + 1)

        except Exception as e:
            logger.error(f"商品信息API请求异常: {self._safe_str(e)}")
            await asyncio.sleep(0.5)
            return await self.get_item_info(item_id, retry_count + 1)

    def extract_item_id_from_message(self, message):
        """从消息中提取商品ID的辅助方法"""
        try:
            # 方法1: 从message["1"]中提取（如果是字符串格式）
            message_1 = message.get('1')
            if isinstance(message_1, str):
                # 尝试从字符串中提取数字ID
                id_match = re.search(r'(\d{10,})', message_1)
                if id_match:
                    logger.info(f"从message[1]字符串中提取商品ID: {id_match.group(1)}")
                    return id_match.group(1)

            # 方法2: 从message["3"]中提取
            message_3 = message.get('3', {})
            if isinstance(message_3, dict):

                # 从extension中提取
                if 'extension' in message_3:
                    extension = message_3['extension']
                    if isinstance(extension, dict):
                        item_id = extension.get('itemId') or extension.get('item_id')
                        if item_id:
                            logger.info(f"从extension中提取商品ID: {item_id}")
                            return item_id

                # 从bizData中提取
                if 'bizData' in message_3:
                    biz_data = message_3['bizData']
                    if isinstance(biz_data, dict):
                        item_id = biz_data.get('itemId') or biz_data.get('item_id')
                        if item_id:
                            logger.info(f"从bizData中提取商品ID: {item_id}")
                            return item_id

                # 从其他可能的字段中提取
                for key, value in message_3.items():
                    if isinstance(value, dict):
                        item_id = value.get('itemId') or value.get('item_id')
                        if item_id:
                            logger.info(f"从{key}字段中提取商品ID: {item_id}")
                            return item_id

                # 从消息内容中提取数字ID
                content = message_3.get('content', '')
                if isinstance(content, str) and content:
                    id_match = re.search(r'(\d{10,})', content)
                    if id_match:
                        logger.info(f"【{self.cookie_id}】从消息内容中提取商品ID: {id_match.group(1)}")
                        return id_match.group(1)

            # 方法3: 遍历整个消息结构查找可能的商品ID
            def find_item_id_recursive(obj, path=""):
                if isinstance(obj, dict):
                    # 直接查找itemId字段
                    for key in ['itemId', 'item_id', 'id']:
                        if key in obj and isinstance(obj[key], (str, int)):
                            value = str(obj[key])
                            if len(value) >= 10 and value.isdigit():
                                logger.info(f"从{path}.{key}中提取商品ID: {value}")
                                return value

                    # 递归查找
                    for key, value in obj.items():
                        result = find_item_id_recursive(value, f"{path}.{key}" if path else key)
                        if result:
                            return result

                elif isinstance(obj, str):
                    # 从字符串中提取可能的商品ID
                    id_match = re.search(r'(\d{10,})', obj)
                    if id_match:
                        logger.info(f"从{path}字符串中提取商品ID: {id_match.group(1)}")
                        return id_match.group(1)

                return None

            result = find_item_id_recursive(message)
            if result:
                return result

            logger.debug("所有方法都未能提取到商品ID")
            return None

        except Exception as e:
            logger.error(f"提取商品ID失败: {self._safe_str(e)}")
            return None

    def debug_message_structure(self, message, context=""):
        """调试消息结构的辅助方法"""
        try:
            logger.debug(f"[{context}] 消息结构调试:")
            logger.debug(f"  消息类型: {type(message)}")

            if isinstance(message, dict):
                for key, value in message.items():
                    logger.debug(f"  键 '{key}': {type(value)} - {str(value)[:100]}...")

                    # 特别关注可能包含商品ID的字段
                    if key in ["1", "3"] and isinstance(value, dict):
                        logger.debug(f"    详细结构 '{key}':")
                        for sub_key, sub_value in value.items():
                            logger.debug(f"      '{sub_key}': {type(sub_value)} - {str(sub_value)[:50]}...")
            else:
                logger.debug(f"  消息内容: {str(message)[:200]}...")

        except Exception as e:
            logger.error(f"调试消息结构时发生错误: {self._safe_str(e)}")

    async def get_default_reply(self, send_user_name: str, send_user_id: str, send_message: str, chat_id: str = None) -> str:
        """获取默认回复内容，支持变量替换和只回复一次功能"""
        try:
            from db_manager import db_manager

            # 获取当前账号的默认回复设置
            default_reply_settings = db_manager.get_default_reply(self.cookie_id)

            if not default_reply_settings or not default_reply_settings.get('enabled', False):
                logger.debug(f"账号 {self.cookie_id} 未启用默认回复")
                return None

            # 检查"只回复一次"功能
            if default_reply_settings.get('reply_once', False) and chat_id:
                # 检查是否已经回复过这个chat_id
                if db_manager.has_default_reply_record(self.cookie_id, chat_id):
                    logger.info(f"【{self.cookie_id}】chat_id {chat_id} 已使用过默认回复，跳过（只回复一次）")
                    return None

            reply_content = default_reply_settings.get('reply_content', '')
            if not reply_content:
                logger.warning(f"账号 {self.cookie_id} 默认回复内容为空")
                return None

            # 进行变量替换
            try:
                formatted_reply = reply_content.format(
                    send_user_name=send_user_name,
                    send_user_id=send_user_id,
                    send_message=send_message
                )

                # 如果开启了"只回复一次"功能，记录这次回复
                if default_reply_settings.get('reply_once', False) and chat_id:
                    db_manager.add_default_reply_record(self.cookie_id, chat_id)
                    logger.info(f"【{self.cookie_id}】记录默认回复: chat_id={chat_id}")

                logger.info(f"【{self.cookie_id}】使用默认回复: {formatted_reply}")
                return formatted_reply
            except Exception as format_error:
                logger.error(f"默认回复变量替换失败: {self._safe_str(format_error)}")
                # 如果变量替换失败，返回原始内容
                return reply_content

        except Exception as e:
            logger.error(f"获取默认回复失败: {self._safe_str(e)}")
            return None

    async def get_keyword_reply_with_type(self, send_user_name: str, send_user_id: str, send_message: str, item_id: str = None) -> tuple:
        """获取关键词匹配回复（支持商品ID优先匹配和图片类型），返回(reply, match_type)"""
        try:
            from db_manager import db_manager

            # 获取当前账号的关键词列表（包含类型信息）
            keywords = db_manager.get_keywords_with_type(self.cookie_id)

            if not keywords:
                logger.debug(f"账号 {self.cookie_id} 没有配置关键词")
                return None, None

            # 1. 如果有商品ID，优先匹配该商品ID对应的关键词
            if item_id:
                for keyword_data in keywords:
                    keyword = keyword_data['keyword']
                    reply = keyword_data['reply']
                    keyword_item_id = keyword_data['item_id']
                    keyword_type = keyword_data.get('type', 'text')
                    image_url = keyword_data.get('image_url')

                    if keyword_item_id == item_id and keyword.lower() in send_message.lower():
                        logger.info(f"商品ID关键词匹配成功: 商品{item_id} '{keyword}' (类型: {keyword_type})")

                        # 根据关键词类型处理
                        if keyword_type == 'image' and image_url:
                            # 图片类型关键词，发送图片
                            reply_result = await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                            return reply_result, 'item_specific'
                        else:
                            # 文本类型关键词，进行变量替换
                            try:
                                formatted_reply = reply.format(
                                    send_user_name=send_user_name,
                                    send_user_id=send_user_id,
                                    send_message=send_message
                                )
                                logger.info(f"商品ID文本关键词回复: {formatted_reply}")
                                return formatted_reply, 'item_specific'
                            except Exception as format_error:
                                logger.error(f"关键词回复变量替换失败: {self._safe_str(format_error)}")
                                # 如果变量替换失败，返回原始内容
                                return reply, 'item_specific'

            # 2. 如果商品ID匹配失败或没有商品ID，匹配没有商品ID的通用关键词
            for keyword_data in keywords:
                keyword = keyword_data['keyword']
                reply = keyword_data['reply']
                keyword_item_id = keyword_data['item_id']
                keyword_type = keyword_data.get('type', 'text')
                image_url = keyword_data.get('image_url')

                if not keyword_item_id and keyword.lower() in send_message.lower():
                    logger.info(f"通用关键词匹配成功: '{keyword}' (类型: {keyword_type})")

                    # 根据关键词类型处理
                    if keyword_type == 'image' and image_url:
                        # 图片类型关键词，发送图片
                        reply_result = await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                        return reply_result, 'account_general'
                    else:
                        # 文本类型关键词，进行变量替换
                        try:
                            formatted_reply = reply.format(
                                send_user_name=send_user_name,
                                send_user_id=send_user_id,
                                send_message=send_message
                            )
                            logger.info(f"通用文本关键词回复: {formatted_reply}")
                            return formatted_reply, 'account_general'
                        except Exception as format_error:
                            logger.error(f"关键词回复变量替换失败: {self._safe_str(format_error)}")
                            # 如果变量替换失败，返回原始内容
                            return reply, 'account_general'

            # 3. 如果账号特定关键词都没有匹配，尝试匹配通用词库
            # 获取当前Cookie对应的用户ID
            cookie_info = db_manager.get_cookie_by_id(self.cookie_id)
            user_id = cookie_info['user_id'] if cookie_info else None
            global_keywords = db_manager.get_enabled_global_keywords(user_id)
            if global_keywords:
                # 导入模糊匹配工具函数
                from utils.message_utils import fuzzy_match_keyword, format_fuzzy_reply
                
                for keyword_data in global_keywords:
                    keyword = keyword_data['keyword']
                    reply = keyword_data['reply']
                    keyword_type = keyword_data.get('type', 'text')
                    image_url = keyword_data.get('image_url')
                    is_fuzzy = keyword_data.get('is_fuzzy', False)

                    # 根据是否是模糊匹配进行不同的匹配逻辑
                    if is_fuzzy:
                        # 模糊匹配
                        is_match, placeholders = fuzzy_match_keyword(keyword, send_message)
                        if is_match:
                            logger.info(f"通用词库模糊关键词匹配成功: '{keyword}' (类型: {keyword_type})")
                            
                            # 根据关键词类型处理
                            if keyword_type == 'image' and image_url:
                                # 图片类型关键词，发送图片
                                reply_result = await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                                return reply_result, 'global'
                            else:
                                # 文本类型关键词，使用模糊匹配的格式化
                                try:
                                    formatted_reply = format_fuzzy_reply(
                                        reply, placeholders, send_user_name, send_user_id, send_message
                                    )
                                    logger.info(f"通用词库模糊关键词回复: {formatted_reply}")
                                    return formatted_reply, 'global'
                                except Exception as format_error:
                                    logger.error(f"通用词库模糊关键词回复格式化失败: {self._safe_str(format_error)}")
                                    # 如果格式化失败，返回原始内容
                                    return reply, 'global'
                    else:
                        # 精确匹配
                        if keyword.lower() in send_message.lower():
                            logger.info(f"通用词库关键词匹配成功: '{keyword}' (类型: {keyword_type})")

                            # 根据关键词类型处理
                            if keyword_type == 'image' and image_url:
                                # 图片类型关键词，发送图片
                                reply_result = await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                                return reply_result, 'global'
                            else:
                                # 文本类型关键词，进行变量替换
                                try:
                                    formatted_reply = reply.format(
                                        send_user_name=send_user_name,
                                        send_user_id=send_user_id,
                                        send_message=send_message
                                    )
                                    logger.info(f"通用词库文本关键词回复: {formatted_reply}")
                                    return formatted_reply, 'global'
                                except Exception as format_error:
                                    logger.error(f"通用词库关键词回复变量替换失败: {self._safe_str(format_error)}")
                                    # 如果变量替换失败，返回原始内容
                                    return reply, 'global'

            logger.debug(f"未找到匹配的关键词（包括通用词库）: {send_message}")
            return None, None

        except Exception as e:
            logger.error(f"获取关键词回复失败: {self._safe_str(e)}")
            return None, None

    async def get_keyword_reply(self, send_user_name: str, send_user_id: str, send_message: str, item_id: str = None) -> str:
        """获取关键词匹配回复（支持商品ID优先匹配和图片类型）"""
        try:
            from db_manager import db_manager

            # 获取当前账号的关键词列表（包含类型信息）
            keywords = db_manager.get_keywords_with_type(self.cookie_id)

            if not keywords:
                logger.debug(f"账号 {self.cookie_id} 没有配置关键词")
                return None

            # 1. 如果有商品ID，优先匹配该商品ID对应的关键词
            if item_id:
                for keyword_data in keywords:
                    keyword = keyword_data['keyword']
                    reply = keyword_data['reply']
                    keyword_item_id = keyword_data['item_id']
                    keyword_type = keyword_data.get('type', 'text')
                    image_url = keyword_data.get('image_url')

                    if keyword_item_id == item_id and keyword.lower() in send_message.lower():
                        logger.info(f"商品ID关键词匹配成功: 商品{item_id} '{keyword}' (类型: {keyword_type})")

                        # 根据关键词类型处理
                        if keyword_type == 'image' and image_url:
                            # 图片类型关键词，发送图片
                            return await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                        else:
                            # 文本类型关键词，进行变量替换
                            try:
                                formatted_reply = reply.format(
                                    send_user_name=send_user_name,
                                    send_user_id=send_user_id,
                                    send_message=send_message
                                )
                                logger.info(f"商品ID文本关键词回复: {formatted_reply}")
                                return formatted_reply
                            except Exception as format_error:
                                logger.error(f"关键词回复变量替换失败: {self._safe_str(format_error)}")
                                # 如果变量替换失败，返回原始内容
                                return reply

            # 2. 如果商品ID匹配失败或没有商品ID，匹配没有商品ID的通用关键词
            for keyword_data in keywords:
                keyword = keyword_data['keyword']
                reply = keyword_data['reply']
                keyword_item_id = keyword_data['item_id']
                keyword_type = keyword_data.get('type', 'text')
                image_url = keyword_data.get('image_url')

                if not keyword_item_id and keyword.lower() in send_message.lower():
                    logger.info(f"通用关键词匹配成功: '{keyword}' (类型: {keyword_type})")

                    # 根据关键词类型处理
                    if keyword_type == 'image' and image_url:
                        # 图片类型关键词，发送图片
                        return await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                    else:
                        # 文本类型关键词，进行变量替换
                        try:
                            formatted_reply = reply.format(
                                send_user_name=send_user_name,
                                send_user_id=send_user_id,
                                send_message=send_message
                            )
                            logger.info(f"通用文本关键词回复: {formatted_reply}")
                            return formatted_reply
                        except Exception as format_error:
                            logger.error(f"关键词回复变量替换失败: {self._safe_str(format_error)}")
                            # 如果变量替换失败，返回原始内容
                            return reply

            # 3. 如果账号特定关键词都没有匹配，尝试匹配通用词库
            # 获取当前Cookie对应的用户ID
            cookie_info = db_manager.get_cookie_by_id(self.cookie_id)
            user_id = cookie_info['user_id'] if cookie_info else None
            global_keywords = db_manager.get_enabled_global_keywords(user_id)
            if global_keywords:
                # 导入模糊匹配工具函数
                from utils.message_utils import fuzzy_match_keyword, format_fuzzy_reply
                
                for keyword_data in global_keywords:
                    keyword = keyword_data['keyword']
                    reply = keyword_data['reply']
                    keyword_type = keyword_data.get('type', 'text')
                    image_url = keyword_data.get('image_url')
                    is_fuzzy = keyword_data.get('is_fuzzy', False)

                    # 根据是否是模糊匹配进行不同的匹配逻辑
                    if is_fuzzy:
                        # 模糊匹配
                        is_match, placeholders = fuzzy_match_keyword(keyword, send_message)
                        if is_match:
                            logger.info(f"通用词库模糊关键词匹配成功: '{keyword}' (类型: {keyword_type})")
                            
                            # 根据关键词类型处理
                            if keyword_type == 'image' and image_url:
                                # 图片类型关键词，发送图片
                                return await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                            else:
                                # 文本类型关键词，使用模糊匹配的格式化
                                try:
                                    formatted_reply = format_fuzzy_reply(
                                        reply, placeholders, send_user_name, send_user_id, send_message
                                    )
                                    logger.info(f"通用词库模糊关键词回复: {formatted_reply}")
                                    return formatted_reply
                                except Exception as format_error:
                                    logger.error(f"通用词库模糊关键词回复格式化失败: {self._safe_str(format_error)}")
                                    # 如果格式化失败，返回原始内容
                                    return reply
                    else:
                        # 精确匹配
                        if keyword.lower() in send_message.lower():
                            logger.info(f"通用词库关键词匹配成功: '{keyword}' (类型: {keyword_type})")

                            # 根据关键词类型处理
                            if keyword_type == 'image' and image_url:
                                # 图片类型关键词，发送图片
                                return await self._handle_image_keyword(keyword, image_url, send_user_name, send_user_id, send_message)
                            else:
                                # 文本类型关键词，进行变量替换
                                try:
                                    formatted_reply = reply.format(
                                        send_user_name=send_user_name,
                                        send_user_id=send_user_id,
                                        send_message=send_message
                                    )
                                    logger.info(f"通用词库文本关键词回复: {formatted_reply}")
                                    return formatted_reply
                                except Exception as format_error:
                                    logger.error(f"通用词库关键词回复变量替换失败: {self._safe_str(format_error)}")
                                    # 如果变量替换失败，返回原始内容
                                    return reply

            logger.debug(f"未找到匹配的关键词（包括通用词库）: {send_message}")
            return None

        except Exception as e:
            logger.error(f"获取关键词回复失败: {self._safe_str(e)}")
            return None

    async def _handle_image_keyword(self, keyword: str, image_url: str, send_user_name: str, send_user_id: str, send_message: str) -> str:
        """处理图片类型关键词"""
        try:
            # 检查图片URL类型
            if self._is_cdn_url(image_url):
                # 已经是CDN链接，直接使用
                logger.info(f"使用已有的CDN图片链接: {image_url}")
                return f"__IMAGE_SEND__{image_url}"

            elif image_url.startswith('/static/uploads/') or image_url.startswith('static/uploads/'):
                # 本地图片，需要上传到闲鱼CDN
                local_image_path = image_url.replace('/static/uploads/', 'static/uploads/').replace('static/uploads/', 'static/uploads/')
                # 标准化路径分隔符
                local_image_path = local_image_path.replace('/', os.sep)
                if os.path.exists(local_image_path):
                    logger.info(f"准备上传本地图片到闲鱼CDN: {local_image_path}")

                    # 使用图片上传器上传到闲鱼CDN
                    from utils.image_uploader import ImageUploader
                    uploader = ImageUploader(self.cookies_str)

                    async with uploader:
                        cdn_url = await uploader.upload_image(local_image_path)
                        if cdn_url:
                            logger.info(f"图片上传成功，CDN URL: {cdn_url}")
                            # 更新数据库中的图片URL为CDN URL
                            await self._update_keyword_image_url(keyword, cdn_url)
                            image_url = cdn_url
                        else:
                            logger.error(f"图片上传失败: {local_image_path}")
                            return f"抱歉，图片发送失败，请稍后重试。"
                else:
                    logger.error(f"本地图片文件不存在: {local_image_path}")
                    return f"抱歉，图片文件不存在。"

            else:
                # 其他类型的URL（可能是外部链接），直接使用
                logger.info(f"使用外部图片链接: {image_url}")

            # 发送图片（这里返回特殊标记，在调用处处理实际发送）
            return f"__IMAGE_SEND__{image_url}"

        except Exception as e:
            logger.error(f"处理图片关键词失败: {e}")
            return f"抱歉，图片发送失败: {str(e)}"

    def _is_cdn_url(self, url: str) -> bool:
        """检查URL是否是闲鱼CDN链接"""
        if not url:
            return False

        # 闲鱼CDN域名列表
        cdn_domains = [
            'gw.alicdn.com',
            'img.alicdn.com',
            'cloud.goofish.com',
            'goofish.com',
            'taobaocdn.com',
            'tbcdn.cn',
            'aliimg.com'
        ]

        # 检查是否包含CDN域名
        url_lower = url.lower()
        for domain in cdn_domains:
            if domain in url_lower:
                return True

        # 检查是否是HTTPS链接且包含图片特征
        if url_lower.startswith('https://') and any(ext in url_lower for ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']):
            return True

        return False

    async def _update_keyword_image_url(self, keyword: str, new_image_url: str):
        """更新关键词的图片URL"""
        try:
            from db_manager import db_manager
            success = db_manager.update_keyword_image_url(self.cookie_id, keyword, new_image_url)
            if success:
                logger.info(f"图片URL已更新: {keyword} -> {new_image_url}")
            else:
                logger.warning(f"图片URL更新失败: {keyword}")
        except Exception as e:
            logger.error(f"更新关键词图片URL失败: {e}")

    async def _update_card_image_url(self, card_id: int, new_image_url: str):
        """更新卡券的图片URL"""
        try:
            from db_manager import db_manager
            success = db_manager.update_card_image_url(card_id, new_image_url)
            if success:
                logger.info(f"卡券图片URL已更新: 卡券ID={card_id} -> {new_image_url}")
            else:
                logger.warning(f"卡券图片URL更新失败: 卡券ID={card_id}")
        except Exception as e:
            logger.error(f"更新卡券图片URL失败: {e}")

    async def get_ai_reply(self, send_user_name: str, send_user_id: str, send_message: str, item_id: str, chat_id: str):
        """获取AI回复"""
        try:
            from ai_reply_engine import ai_reply_engine

            # 检查是否启用AI回复
            if not ai_reply_engine.is_ai_enabled(self.cookie_id):
                logger.debug(f"账号 {self.cookie_id} 未启用AI回复")
                return None

            # 从数据库获取商品信息
            from db_manager import db_manager
            item_info_raw = db_manager.get_item_info(self.cookie_id, item_id)

            if not item_info_raw:
                logger.debug(f"数据库中无商品信息: {item_id}")
                # 使用默认商品信息
                item_info = {
                    'title': '商品信息获取失败',
                    'price': 0,
                    'desc': '暂无商品描述'
                }
            else:
                # 解析数据库中的商品信息
                item_info = {
                    'title': item_info_raw.get('item_title', '未知商品'),
                    'price': self._parse_price(item_info_raw.get('item_price', '0')),
                    'desc': item_info_raw.get('item_description', '暂无商品描述')
                }

            # 生成AI回复
            reply = ai_reply_engine.generate_reply(
                message=send_message,
                item_info=item_info,
                chat_id=chat_id,
                cookie_id=self.cookie_id,
                user_id=send_user_id,
                item_id=item_id
            )

            if reply:
                logger.info(f"【{self.cookie_id}】AI回复生成成功: {reply}")
                return reply
            else:
                logger.debug(f"AI回复生成失败")
                return None

        except Exception as e:
            logger.error(f"获取AI回复失败: {self._safe_str(e)}")
            return None

    def _parse_price(self, price_str: str) -> float:
        """解析价格字符串为数字"""
        try:
            if not price_str:
                return 0.0
            # 移除非数字字符，保留小数点
            price_clean = re.sub(r'[^\d.]', '', str(price_str))
            return float(price_clean) if price_clean else 0.0
        except:
            return 0.0

    async def send_notification(self, send_user_name: str, send_user_id: str, send_message: str, item_id: str = None):
        """发送消息通知 - 已关闭未成功匹配消息内容通知功能"""
        # 注释掉整个方法实现，关闭"未成功匹配消息内容通知"功能
        logger.debug(f"未成功匹配消息内容通知功能已关闭 - 账号: {self.cookie_id}, 用户: {send_user_name}")
        return

        # 以下代码已被注释，用于关闭"未成功匹配消息内容通知"功能
        # try:
        #     from db_manager import db_manager
        #     import aiohttp

        #     # 获取当前账号的通知配置
        #     notifications = db_manager.get_account_notifications(self.cookie_id)

        #     if not notifications:
        #         logger.debug(f"账号 {self.cookie_id} 未配置消息通知")
        #         return

        #     # 获取账号备注信息
        #     cookie_details = db_manager.get_cookie_details(self.cookie_id)
        #     account_remark = cookie_details.get('remark', '') if cookie_details else ''

        #     # 构建通知消息，包含账号备注
        #     notification_msg = f"🚨 未成功匹配消息内容通知\n\n" \
        #                      f"账号: {self.cookie_id}\n"

        #     # 如果有备注，添加到通知消息中
        #     if account_remark:
        #         notification_msg += f"备注: {account_remark}\n"

        #     notification_msg += f"买家: {send_user_name} (ID: {send_user_id})\n" \
        #                      f"商品ID: {item_id or '未知'}\n" \
        #                      f"消息内容: {send_message}\n" \
        #                      f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n"

        #     # 发送通知到各个渠道
        #     for notification in notifications:
        #         if not notification.get('enabled', True):
        #             continue

        #         channel_type = notification.get('channel_type')
        #         channel_config = notification.get('channel_config')

        #         try:
        #             # 解析配置数据
        #             config_data = self._parse_notification_config(channel_config)

        #             if channel_type in ['ding_talk', 'dingtalk']:
        #                 await self._send_dingtalk_notification(config_data, notification_msg)
        #             elif channel_type == 'email':
        #                 await self._send_email_notification(config_data, notification_msg)
        #             elif channel_type == 'webhook':
        #                 await self._send_webhook_notification(config_data, notification_msg)
        #             elif channel_type == 'wechat':
        #                 await self._send_wechat_notification(config_data, notification_msg)
        #             elif channel_type == 'telegram':
        #                 await self._send_telegram_notification(config_data, notification_msg)
        #             else:
        #                 logger.warning(f"不支持的通知渠道类型: {channel_type}")

        #         except Exception as notify_error:
        #             logger.error(f"发送通知失败 ({notification.get('channel_name', 'Unknown')}): {self._safe_str(notify_error)}")

        # except Exception as e:
        #     logger.error(f"处理消息通知失败: {self._safe_str(e)}")

    def _update_token_status_based_on_connection(self, is_connected: bool):
        """根据WebSocket连接状态更新Token状态"""
        try:
            from db_manager import db_manager
            current_status = db_manager.get_token_status(self.cookie_id)

            if is_connected and current_status == 'invalid':
                # WebSocket连接成功且当前状态为失效，更新为有效
                db_manager.update_token_status(self.cookie_id, 'valid')
                logger.info(f"【{self.cookie_id}】WebSocket连接成功，Token状态已更新为有效")
            elif not is_connected and current_status == 'valid':
                # 连接失败但不立即设置为失效，等待重连尝试
                logger.info(f"【{self.cookie_id}】WebSocket连接失败，但保持Token状态不变，等待重连")
        except Exception as e:
            logger.error(f"【{self.cookie_id}】更新Token状态失败: {self._safe_str(e)}")

    def _parse_notification_config(self, config: str) -> dict:
        """解析通知配置数据"""
        try:
            # 尝试解析JSON格式的配置
            return json.loads(config)
        except (json.JSONDecodeError, TypeError):
            # 兼容旧格式（直接字符串）
            return {"config": config}



    async def _send_dingtalk_notification(self, config_data: dict, message: str):
        """发送钉钉通知"""
        try:
            import aiohttp
            import hmac
            import hashlib
            import base64
            import time

            # 解析配置
            webhook_url = config_data.get('webhook_url') or config_data.get('config', '')
            secret = config_data.get('secret', '')

            webhook_url = webhook_url.strip() if webhook_url else ''
            if not webhook_url:
                logger.warning("钉钉通知配置为空")
                return

            # 如果有加签密钥，生成签名
            if secret:
                timestamp = str(round(time.time() * 1000))
                secret_enc = secret.encode('utf-8')
                string_to_sign = f'{timestamp}\n{secret}'
                string_to_sign_enc = string_to_sign.encode('utf-8')
                hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
                sign = base64.b64encode(hmac_code).decode('utf-8')
                webhook_url += f'&timestamp={timestamp}&sign={sign}'

            data = {
                "msgtype": "markdown",
                "markdown": {
                    "title": "闲鱼自动回复通知",
                    "text": message
                }
            }

            async with aiohttp.ClientSession() as session:
                async with session.post(webhook_url, json=data, timeout=10) as response:
                    if response.status == 200:
                        logger.info(f"钉钉通知发送成功")
                    else:
                        logger.warning(f"钉钉通知发送失败: {response.status}")

        except Exception as e:
            logger.error(f"发送钉钉通知异常: {self._safe_str(e)}")

    async def _send_email_notification(self, config_data: dict, message: str):
        """发送邮件通知"""
        try:
            import smtplib
            from email.mime.text import MIMEText
            from email.mime.multipart import MIMEMultipart

            # 解析配置
            smtp_server = config_data.get('smtp_server', '')
            smtp_port = int(config_data.get('smtp_port', 587))
            email_user = config_data.get('email_user', '')
            email_password = config_data.get('email_password', '')
            recipient_email = config_data.get('recipient_email', '')

            if not all([smtp_server, email_user, email_password, recipient_email]):
                logger.warning("邮件通知配置不完整")
                return

            # 创建邮件
            msg = MIMEMultipart()
            msg['From'] = email_user
            msg['To'] = recipient_email
            msg['Subject'] = "闲鱼自动回复通知"

            # 添加邮件正文
            msg.attach(MIMEText(message, 'plain', 'utf-8'))

            # 发送邮件
            server = smtplib.SMTP(smtp_server, smtp_port)
            server.starttls()
            server.login(email_user, email_password)
            server.send_message(msg)
            server.quit()

            logger.info(f"邮件通知发送成功: {recipient_email}")

        except Exception as e:
            logger.error(f"发送邮件通知异常: {self._safe_str(e)}")

    async def _send_webhook_notification(self, config_data: dict, message: str):
        """发送Webhook通知"""
        try:
            import aiohttp
            import time

            # 解析配置
            webhook_url = config_data.get('webhook_url', '')
            http_method = config_data.get('http_method', 'POST').upper()
            headers_str = config_data.get('headers', '{}')
            api_format = config_data.get('api_format', 'generic')
            wxid_param = config_data.get('wxid_param', '')
            target_wxid = config_data.get('target_wxid', '')

            if not webhook_url:
                logger.warning("Webhook通知配置为空")
                return

            # 检查是否为微信机器人格式，如果是则优先使用账号专属wxid
            if api_format == 'wechat_bot':
                from db_manager import db_manager
                cookie_details = db_manager.get_cookie_details(self.cookie_id)
                if cookie_details and cookie_details.get('notification_wxid'):
                    # 使用账号专属wxid替换目标wxid
                    target_wxid = cookie_details['notification_wxid']
                    logger.info(f"使用账号专属通知wxid: {target_wxid}")

            # 构建完整的URL（如果是微信机器人格式且有wxid参数）
            final_url = webhook_url
            if api_format == 'wechat_bot' and wxid_param:
                separator = '&' if '?' in webhook_url else '?'
                final_url = f"{webhook_url}{separator}wxid={wxid_param}"

            # 解析自定义请求头
            try:
                custom_headers = json.loads(headers_str) if headers_str else {}
            except json.JSONDecodeError:
                custom_headers = {}

            # 设置默认请求头
            headers = {'Content-Type': 'application/json'}
            headers.update(custom_headers)

            # 根据API格式构建请求数据
            if api_format == 'wechat_bot':
                # 微信机器人API格式
                data = {
                    "type": "sendText",
                    "data": {
                        "wxid": target_wxid or "default_wxid",
                        "msg": message
                    }
                }
            else:
                # 通用格式（原有格式）
                data = {
                    'message': message,
                    'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
                    'source': 'xianyu-auto-reply'
                }

            async with aiohttp.ClientSession() as session:
                if http_method == 'POST':
                    async with session.post(final_url, json=data, headers=headers, timeout=10) as response:
                        if response.status == 200:
                            logger.info(f"Webhook通知发送成功 (格式: {api_format})")
                        else:
                            response_text = await response.text()
                            logger.warning(f"Webhook通知发送失败: {response.status}, 响应: {response_text}")
                elif http_method == 'PUT':
                    async with session.put(final_url, json=data, headers=headers, timeout=10) as response:
                        if response.status == 200:
                            logger.info(f"Webhook通知发送成功 (格式: {api_format})")
                        else:
                            response_text = await response.text()
                            logger.warning(f"Webhook通知发送失败: {response.status}, 响应: {response_text}")
                else:
                    logger.warning(f"不支持的HTTP方法: {http_method}")

        except Exception as e:
            logger.error(f"发送Webhook通知异常: {self._safe_str(e)}")

    async def _send_wechat_notification(self, config_data: dict, message: str):
        """发送微信通知"""
        try:
            import aiohttp

            # 解析配置
            webhook_url = config_data.get('webhook_url', '')

            if not webhook_url:
                logger.warning("微信通知配置为空")
                return

            data = {
                "msgtype": "text",
                "text": {
                    "content": message
                }
            }

            async with aiohttp.ClientSession() as session:
                async with session.post(webhook_url, json=data, timeout=10) as response:
                    if response.status == 200:
                        logger.info(f"微信通知发送成功")
                    else:
                        logger.warning(f"微信通知发送失败: {response.status}")

        except Exception as e:
            logger.error(f"发送微信通知异常: {self._safe_str(e)}")

    async def _send_telegram_notification(self, config_data: dict, message: str):
        """发送Telegram通知"""
        try:
            import aiohttp

            # 解析配置
            bot_token = config_data.get('bot_token', '')
            chat_id = config_data.get('chat_id', '')

            if not all([bot_token, chat_id]):
                logger.warning("Telegram通知配置不完整")
                return

            # 构建API URL
            api_url = f"https://api.telegram.org/bot{bot_token}/sendMessage"

            data = {
                'chat_id': chat_id,
                'text': message,
                'parse_mode': 'HTML'
            }

            async with aiohttp.ClientSession() as session:
                async with session.post(api_url, json=data, timeout=10) as response:
                    if response.status == 200:
                        logger.info(f"Telegram通知发送成功")
                    else:
                        logger.warning(f"Telegram通知发送失败: {response.status}")

        except Exception as e:
            logger.error(f"发送Telegram通知异常: {self._safe_str(e)}")

    async def send_token_refresh_notification(self, error_message: str, notification_type: str = "token_refresh"):
        """发送Token刷新异常通知（带防重复机制）"""
        try:
            # 检查是否是正常的令牌过期，这种情况不需要发送通知
            if self._is_normal_token_expiry(error_message):
                logger.debug(f"检测到正常的令牌过期，跳过通知: {error_message}")
                return

            # 检查是否在冷却期内
            current_time = time.time()
            
            # 对于Token相关的通知，统一使用 "token_related" 作为冷却key
            # 这样可以防止不同类型的Token通知重复发送
            if self._is_token_related_error(error_message):
                cooldown_key = "token_related"
            else:
                cooldown_key = notification_type
            
            last_time = self.last_notification_time.get(cooldown_key, 0)

            # 为Token刷新异常通知使用特殊的24小时冷却时间
            # 基于错误消息内容判断是否为Token相关异常
            if self._is_token_related_error(error_message):
                cooldown_time = self.token_refresh_notification_cooldown
                cooldown_desc = "24小时"
            else:
                cooldown_time = self.notification_cooldown
                cooldown_desc = f"{self.notification_cooldown // 60}分钟"

            if current_time - last_time < cooldown_time:
                remaining_time = cooldown_time - (current_time - last_time)
                remaining_hours = int(remaining_time // 3600)
                remaining_minutes = int((remaining_time % 3600) // 60)
                remaining_seconds = int(remaining_time % 60)

                if remaining_hours > 0:
                    time_desc = f"{remaining_hours}小时{remaining_minutes}分钟"
                elif remaining_minutes > 0:
                    time_desc = f"{remaining_minutes}分钟{remaining_seconds}秒"
                else:
                    time_desc = f"{remaining_seconds}秒"

                logger.debug(f"Token刷新通知在冷却期内，跳过发送: {cooldown_key} (还需等待 {time_desc})")
                return

            from db_manager import db_manager

            # 获取当前账号的通知配置
            notifications = db_manager.get_message_notifications(self.cookie_id)

            if not notifications:
                logger.debug("未配置消息通知，跳过Token刷新通知")
                return

            # 获取账号备注信息
            cookie_details = db_manager.get_cookie_details(self.cookie_id)
            account_remark = cookie_details.get('remark', '') if cookie_details else ''
            
            # 构造通知消息
            notification_msg = f"""🔴 闲鱼账号Token刷新异常

账号ID: {self.cookie_id}"""
            
            # 如果有备注，添加到通知消息中
            if account_remark:
                notification_msg += f"\n备注: {account_remark}"
                
            notification_msg += f"""
异常时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}
异常信息: {error_message}

请检查账号Cookie是否过期，如有需要请及时更新Cookie配置。"""

            logger.info(f"准备发送Token刷新异常通知: {self.cookie_id}")

            # 发送通知到各个渠道
            notification_sent = False
            for notification in notifications:
                if not notification.get('enabled', True):
                    continue

                channel_type = notification.get('channel_type')
                channel_config = notification.get('config')

                try:
                    # 解析配置数据
                    config_data = self._parse_notification_config(channel_config)

                    if channel_type in ['ding_talk', 'dingtalk']:
                        await self._send_dingtalk_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'email':
                        await self._send_email_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'webhook':
                        await self._send_webhook_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'wechat':
                        await self._send_wechat_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'telegram':
                        await self._send_telegram_notification(config_data, notification_msg)
                        notification_sent = True
                    else:
                        logger.warning(f"不支持的通知渠道类型: {channel_type}")

                except Exception as notify_error:
                    logger.error(f"发送Token刷新通知失败 ({notification.get('channel_name', 'Unknown')}): {self._safe_str(notify_error)}")

            # 如果成功发送了通知，更新最后发送时间
            if notification_sent:
                self.last_notification_time[cooldown_key] = current_time

                # 根据错误消息内容使用不同的冷却时间
                if self._is_token_related_error(error_message):
                    next_send_time = current_time + self.token_refresh_notification_cooldown
                    cooldown_desc = "24小时"
                else:
                    next_send_time = current_time + self.notification_cooldown
                    cooldown_desc = f"{self.notification_cooldown // 60}分钟"

                next_send_time_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(next_send_time))
                logger.info(f"Token刷新通知已发送，下次可发送时间: {next_send_time_str} (冷却时间: {cooldown_desc})")

        except Exception as e:
            logger.error(f"处理Token刷新通知失败: {self._safe_str(e)}")

    def _is_normal_token_expiry(self, error_message: str) -> bool:
        """检查是否是正常的令牌过期或其他不需要通知的情况"""
        # 不需要发送通知的关键词
        no_notification_keywords = [
            # 正常的令牌过期
            'FAIL_SYS_TOKEN_EXOIRED::令牌过期',
            'FAIL_SYS_TOKEN_EXPIRED::令牌过期',
            'FAIL_SYS_TOKEN_EXOIRED',
            'FAIL_SYS_TOKEN_EXPIRED',
            '令牌过期',
            # Session过期（正常情况）
            'FAIL_SYS_SESSION_EXPIRED::Session过期',
            'FAIL_SYS_SESSION_EXPIRED',
            'Session过期',
            # Token定时刷新失败（会自动重试）
            'Token定时刷新失败，将自动重试',
            'Token定时刷新失败'
        ]

        # 检查错误消息是否包含不需要通知的关键词
        for keyword in no_notification_keywords:
            if keyword in error_message:
                return True

        return False

    def _is_token_related_error(self, error_message: str) -> bool:
        """检查是否是Token相关的错误，需要使用24小时冷却时间"""
        # Token相关错误的关键词
        token_error_keywords = [
            # Token刷新失败相关
            'Token刷新失败',
            'Token刷新异常',
            'token刷新失败',
            'token刷新异常',
            'TOKEN刷新失败',
            'TOKEN刷新异常',
            # Token失效相关 - 新增
            'Token已失效',
            'token已失效',
            'TOKEN已失效',
            'Token失效',
            'token失效',
            'TOKEN失效',
            # 具体的Token错误信息
            'FAIL_SYS_USER_VALIDATE',
            'RGV587_ERROR',
            '哎哟喂,被挤爆啦',
            '请稍后重试',
            'punish?x5secdata',
            'captcha',
            # Token获取失败
            '无法获取有效token',
            '无法获取有效Token',
            'Token获取失败',
            'token获取失败',
            'TOKEN获取失败',
            # Token定时刷新失败
            'Token定时刷新失败',
            'token定时刷新失败',
            'TOKEN定时刷新失败',
            # 初始化Token失败
            '初始化时无法获取有效Token',
            '初始化时无法获取有效token',
            # 其他Token相关错误
            'accessToken',
            'access_token',
            '_m_h5_tk',
            'mtop.taobao.idlemessage.pc.login.token'
        ]

        # 检查错误消息是否包含Token相关的关键词
        error_message_lower = error_message.lower()
        for keyword in token_error_keywords:
            if keyword.lower() in error_message_lower:
                return True

        return False

    async def send_delivery_failure_notification(self, send_user_name: str, send_user_id: str, item_id: str, error_message: str):
        """发送自动发货失败通知"""
        try:
            from db_manager import db_manager

            # 获取当前账号的通知配置
            notifications = db_manager.get_message_notifications(self.cookie_id)

            if not notifications:
                logger.debug("未配置消息通知，跳过自动发货通知")
                return

            # 获取账号备注信息
            cookie_details = db_manager.get_cookie_details(self.cookie_id)
            account_remark = cookie_details.get('remark', '') if cookie_details else ''
            
            # 构造通知消息
            notification_message = f"🚨 自动发货通知\n\n" \
                                 f"账号: {self.cookie_id}\n"
            
            # 如果有备注，添加到通知消息中
            if account_remark:
                notification_message += f"备注: {account_remark}\n"
                
            notification_message += f"买家: {send_user_name} (ID: {send_user_id})\n" \
                                 f"商品ID: {item_id}\n" \
                                 f"结果: {error_message}\n" \
                                 f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n" \
                                 f"请及时处理！"

            # 发送通知到所有已启用的通知渠道
            for notification in notifications:
                if notification.get('enabled', False):
                    channel_type = notification.get('channel_type', 'dingtalk')
                    channel_config = notification.get('config', '')

                    try:
                        # 解析配置数据
                        config_data = self._parse_notification_config(channel_config)

                        if channel_type in ['ding_talk', 'dingtalk']:
                            await self._send_dingtalk_notification(config_data, notification_message)
                            logger.info(f"已发送自动发货通知到钉钉")
                        elif channel_type == 'email':
                            await self._send_email_notification(config_data, notification_message)
                            logger.info(f"已发送自动发货通知到邮箱")
                        elif channel_type == 'webhook':
                            await self._send_webhook_notification(config_data, notification_message)
                            logger.info(f"已发送自动发货通知到Webhook")
                        elif channel_type == 'wechat':
                            await self._send_wechat_notification(config_data, notification_message)
                            logger.info(f"已发送自动发货通知到微信")
                        elif channel_type == 'telegram':
                            await self._send_telegram_notification(config_data, notification_message)
                            logger.info(f"已发送自动发货通知到Telegram")
                        else:
                            logger.warning(f"不支持的通知渠道类型: {channel_type}")

                    except Exception as notify_error:
                        logger.error(f"发送自动发货通知失败: {self._safe_str(notify_error)}")

        except Exception as e:
            logger.error(f"发送自动发货通知异常: {self._safe_str(e)}")

    async def auto_confirm(self, order_id, item_id=None, retry_count=0):
        """自动确认发货 - 使用解密模块"""
        try:
            logger.debug(f"【{self.cookie_id}】开始确认发货，订单ID: {order_id}")

            # 导入解密确认模块
            from secure_confirm_decrypted import SecureConfirm

            # 创建解密确认实例
            secure_confirm = SecureConfirm(self.session, self.cookies_str, self.cookie_id, self)

            # 调用解密的确认方法
            return await secure_confirm.auto_confirm(order_id, item_id, retry_count)

        except Exception as e:
            logger.error(f"【{self.cookie_id}】解密确认模块调用失败: {self._safe_str(e)}")
            return {"error": f"解密确认模块调用失败: {self._safe_str(e)}", "order_id": order_id}

    async def auto_freeshipping(self, order_id, item_id, buyer_id, retry_count=0):
        """自动免拼发货 - 使用解密模块"""
        try:
            logger.debug(f"【{self.cookie_id}】开始免拼发货，订单ID: {order_id}")

            # 导入解密免拼发货模块
            from secure_freeshipping_decrypted import SecureFreeshipping

            # 创建解密免拼发货实例
            secure_freeshipping = SecureFreeshipping(self.session, self.cookies_str, self.cookie_id)

            # 调用解密的免拼发货方法
            return await secure_freeshipping.auto_freeshipping(order_id, item_id, buyer_id, retry_count)

        except Exception as e:
            logger.error(f"【{self.cookie_id}】解密免拼发货模块调用失败: {self._safe_str(e)}")
            return {"error": f"解密免拼发货模块调用失败: {self._safe_str(e)}", "order_id": order_id}

    async def fetch_order_detail_info(self, order_id: str, item_id: str = None, buyer_id: str = None, debug_headless: bool = None):
        """获取订单详情信息"""
        # 防重复获取机制
        lock_key = f"{self.cookie_id}_{order_id}"
        
        async with self._order_detail_lock:
            if lock_key in self._order_detail_locks:
                logger.info(f"【{self.cookie_id}】订单 {order_id} 正在获取详情中，跳过重复请求")
                return None
            
            # 创建锁
            self._order_detail_locks[lock_key] = asyncio.Lock()
        
        async with self._order_detail_locks[lock_key]:
            try:
                logger.info(f"【{self.cookie_id}】开始获取订单详情: {order_id}")
                
                # 检查数据库中是否已有完整的订单详情
                from db_manager import db_manager
                existing_order = db_manager.get_order_by_id_enhanced(order_id)
                if existing_order and existing_order.get('amount') and existing_order.get('quantity'):
                    logger.info(f"【{self.cookie_id}】订单 {order_id} 详情已存在，跳过获取")
                    return existing_order

                # 导入订单详情获取器
                from utils.order_detail_fetcher import fetch_order_detail_simple

                # 获取当前账号的cookie字符串
                cookie_string = self.cookies_str
                logger.debug(f"【{self.cookie_id}】使用Cookie长度: {len(cookie_string) if cookie_string else 0}")

                # 确定是否使用无头模式
                if debug_headless is not None:
                    headless_mode = not debug_headless  # debug_headless=True表示显示浏览器
                else:
                    headless_mode = True  # 默认使用无头模式

                # 异步获取订单详情（使用当前账号的cookie，优先使用API方式）
                result = await fetch_order_detail_simple(order_id, cookie_string, headless=headless_mode, use_api=True)

                if result:
                    logger.info(f"【{self.cookie_id}】订单详情获取成功: {order_id}")
                    logger.info(f"【{self.cookie_id}】页面标题: {result.get('title', '未知')}")

                    # 获取解析后的规格信息
                    spec_name = result.get('spec_name', '')
                    spec_value = result.get('spec_value', '')
                    quantity = result.get('quantity', '')
                    amount = result.get('amount', '')

                    # 打印获取到的信息（无论是否有规格）
                    logger.info(f"【{self.cookie_id}】📦 数量: {quantity}")
                    logger.info(f"【{self.cookie_id}】💰 金额: {amount}")
                    print(f"📦 【{self.cookie_id}】订单 {order_id} 数量: {quantity}")
                    print(f"💰 【{self.cookie_id}】订单 {order_id} 金额: {amount}")

                    if spec_name and spec_value:
                        logger.info(f"【{self.cookie_id}】📋 规格名称: {spec_name}")
                        logger.info(f"【{self.cookie_id}】📝 规格值: {spec_value}")
                        print(f"🛍️ 【{self.cookie_id}】订单 {order_id} 规格信息: {spec_name} -> {spec_value}")
                    else:
                        logger.info(f"【{self.cookie_id}】该商品无规格选项")
                        print(f"ℹ️ 【{self.cookie_id}】订单 {order_id} 该商品无规格选项")

                    # 检查是否是自动发货后的订单详情获取（通过检查订单是否已存在且状态为"已发货"）
                    try:
                        # 检查cookie_id是否在cookies表中存在
                        cookie_info = db_manager.get_cookie_by_id(self.cookie_id)
                        if not cookie_info:
                            logger.warning(f"Cookie ID {self.cookie_id} 不存在于cookies表中，丢弃订单 {order_id}")
                        else:
                            # 检查订单是否已存在且状态为"已发货"（说明是自动发货成功后的详情获取）
                            existing_order = db_manager.get_order_by_id(order_id, self.cookie_id)
                            
                            if existing_order and existing_order.get('order_status') == '已发货':
                                # 这是自动发货成功后的详情获取，更新订单的详细信息
                                success = db_manager.insert_or_update_order(
                                    order_id=order_id,
                                    item_id=item_id,
                                    buyer_id=buyer_id,
                                    spec_name=spec_name,
                                    spec_value=spec_value,
                                    quantity=quantity,
                                    amount=amount,
                                    order_status=None,  # 不改变现有状态
                                    cookie_id=self.cookie_id
                                )

                                if success:
                                    logger.info(f"【{self.cookie_id}】自动发货订单详细信息已更新到数据库: {order_id}")
                                    print(f"💾 【{self.cookie_id}】自动发货订单 {order_id} 详细信息已更新到数据库")
                                else:
                                    logger.warning(f"【{self.cookie_id}】自动发货订单详细信息更新失败: {order_id}")
                            else:
                                # 这是普通的订单详情获取，不保存到数据库，避免多规格未触发自动发货的订单显示在列表中
                                logger.debug(f"【{self.cookie_id}】普通订单详情获取完成，未触发自动发货，不保存到数据库: {order_id}")

                    except Exception as db_e:
                        logger.error(f"【{self.cookie_id}】处理订单信息时失败: {self._safe_str(db_e)}")

                    return result
                else:
                    logger.warning(f"【{self.cookie_id}】订单详情获取失败: {order_id}")
                    return None

            except Exception as e:
                logger.error(f"【{self.cookie_id}】获取订单详情异常: {self._safe_str(e)}")
                return None
            finally:
                # 清理锁
                async with self._order_detail_lock:
                    if lock_key in self._order_detail_locks:
                        del self._order_detail_locks[lock_key]

    async def _add_delayed_guide_task(self, user_id: str, chat_id: str, item_id: str = None):
        """添加延迟引导话术任务"""
        try:
            from db_manager import db_manager
            
            # 检查是否启用延迟引导功能
            enabled = db_manager.get_system_setting('delayed_guide_enabled')
            if enabled != 'true':
                logger.debug("延迟引导功能已禁用")
                return
            
            # 获取延迟时间设置
            delay_setting = db_manager.get_system_setting('delayed_guide_delay_seconds')
            delay_seconds = int(delay_setting) if delay_setting and delay_setting.isdigit() else 60
            
            # 取消该对话中之前的所有待发送任务
            db_manager.cancel_delayed_guide_tasks(self.cookie_id, user_id, chat_id)
            
            # 添加新的延迟引导任务
            task_id = db_manager.add_delayed_guide_task(
                self.cookie_id, user_id, chat_id, item_id, delay_seconds
            )
            
            if task_id > 0:
                logger.info(f"成功添加延迟引导任务: {task_id}, 将在 {delay_seconds} 秒后检查")
            else:
                logger.warning("添加延迟引导任务失败")
                
        except Exception as e:
            logger.error(f"添加延迟引导任务异常: {self._safe_str(e)}")

    async def _auto_delivery(self, item_id: str, item_title: str = None, order_id: str = None):
        """自动发货功能 - 获取卡券规则，执行延时，确认发货，发送内容"""
        try:
            from db_manager import db_manager

            # 在自动发货前先检查用户余额
            user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
            if not user_id:
                logger.error(f"【{self.cookie_id}】无法获取用户ID，取消自动发货")
                return None
            
            # 检查用户是否有足够余额进行自动发货（需要10聚合豆）
            current_balance = db_manager.get_user_balance(user_id)
            if current_balance < 10.0:
                logger.warning(f"【{self.cookie_id}】用户余额不足(当前:{current_balance}聚合豆，需要:10聚合豆)，取消自动发货")
                return None

            logger.info(f"开始自动发货检查: 商品ID={item_id}, 用户余额={current_balance}聚合豆")

            # 获取商品详细信息
            item_info = None
            search_text = item_title  # 默认使用传入的标题

            if item_id and item_id != "未知商品":
                # 优先尝试通过API获取商品信息
                try:
                    logger.debug(f"通过API获取商品详细信息: {item_id}")
                    item_info = await self.get_item_info(item_id)
                    if item_info and 'data' in item_info:
                        data = item_info['data']
                        item_data = data['itemDO']
                        shareData = item_data['shareData']
                        shareInfoJsonString = shareData['shareInfoJsonString']

                        # 解析 shareInfoJsonString 并提取 content 内容
                        try:
                            share_info = json.loads(shareInfoJsonString)
                            content = share_info.get('contentParams', {}).get('mainParams', {}).get('content', '')
                            if content:
                                search_text = content
                                logger.debug(f"API成功提取商品内容作为搜索文本: {content[:100]}...")
                            else:
                                search_text = shareInfoJsonString
                                logger.debug("未能从API商品信息中提取到content字段，使用完整JSON字符串")
                        except json.JSONDecodeError as json_e:
                            logger.warning(f"解析API商品信息JSON失败: {self._safe_str(json_e)}，使用原始字符串")
                            search_text = shareInfoJsonString
                        except Exception as parse_e:
                            logger.warning(f"提取API商品内容失败: {self._safe_str(parse_e)}，使用原始字符串")
                            search_text = shareInfoJsonString

                        logger.debug(f"API获取到的商品信息为: {search_text[:200]}...")
                    else:
                        raise Exception("API返回数据格式异常")

                except Exception as e:
                    logger.warning(f"API获取商品信息失败: {self._safe_str(e)}，尝试从数据库获取")

                    # API失败时，从数据库获取商品信息
                    try:
                        db_item_info = db_manager.get_item_info(self.cookie_id, item_id)
                        if db_item_info:
                            # 拼接商品标题和详情作为搜索文本
                            item_title_db = db_item_info.get('item_title', '') or ''
                            item_detail_db = db_item_info.get('item_detail', '') or ''

                            # 如果数据库中没有详情，尝试从外部API获取
                            if not item_detail_db.strip():
                                from config import config
                                auto_fetch_config = config.get('ITEM_DETAIL', {}).get('auto_fetch', {})

                                if auto_fetch_config.get('enabled', True):
                                    logger.info(f"数据库中商品详情为空，尝试从外部API获取: {item_id}")
                                    try:
                                        fetched_detail = await self.fetch_item_detail_from_api(item_id)
                                        if fetched_detail:
                                            # 保存获取到的详情
                                            await self.save_item_detail_only(item_id, fetched_detail)
                                            item_detail_db = fetched_detail
                                            logger.info(f"成功从外部API获取并保存商品详情: {item_id}")
                                        else:
                                            logger.warning(f"外部API未能获取到商品详情: {item_id}")
                                    except Exception as api_e:
                                        logger.warning(f"从外部API获取商品详情失败: {item_id}, 错误: {self._safe_str(api_e)}")
                                else:
                                    logger.debug(f"自动获取商品详情功能已禁用，跳过: {item_id}")

                            # 组合搜索文本：商品标题 + 商品详情
                            search_parts = []
                            if item_title_db.strip():
                                search_parts.append(item_title_db.strip())
                            if item_detail_db.strip():
                                search_parts.append(item_detail_db.strip())

                            if search_parts:
                                search_text = ' '.join(search_parts)
                                logger.info(f"使用数据库商品标题+详情作为搜索文本: 标题='{item_title_db}', 详情长度={len(item_detail_db)}")
                                logger.debug(f"完整搜索文本: {search_text[:200]}...")
                            else:
                                logger.warning(f"数据库中商品标题和详情都为空，且无法从API获取: {item_id}")
                                search_text = item_title or item_id
                        else:
                            logger.debug(f"数据库中未找到商品信息: {item_id}")
                            search_text = item_title or item_id

                    except Exception as db_e:
                        logger.debug(f"从数据库获取商品信息失败: {self._safe_str(db_e)}")
                        search_text = item_title or item_id

            if not search_text:
                search_text = item_id or "未知商品"

            logger.debug(f"使用搜索文本匹配发货规则: {search_text[:100]}...")

            # 预检查发货规则 - 避免不必要的订单详情获取
            logger.debug(f"预检查商品ID {item_id} 的发货规则")
            delivery_rules = db_manager.get_delivery_rules_by_item_id(item_id, user_id)

            if not delivery_rules:
                logger.debug(f"❌ 未找到商品ID {item_id} 的发货规则，跳过自动发货")
                return None

            logger.info(f"✅ 找到匹配的发货规则: {len(delivery_rules)}个")

            # 检查是否有多规格发货规则
            has_multi_spec_rules = any(rule.get('rule_is_multi_spec') for rule in delivery_rules)
            spec_name = None
            spec_value = None

            # 如果有多规格发货规则且有订单ID，获取规格信息
            if has_multi_spec_rules and order_id:
                logger.info(f"检测到多规格发货规则，获取订单规格信息: {order_id}")
                try:
                    order_detail = await self.fetch_order_detail_info(order_id)
                    if order_detail:
                        spec_name = order_detail.get('spec_name', '')
                        spec_value = order_detail.get('spec_value', '')
                        if spec_name and spec_value:
                            logger.info(f"获取到规格信息: {spec_name} = {spec_value}")
                        else:
                            logger.warning(f"未能获取到规格信息，将使用兜底匹配")
                    else:
                        logger.warning(f"获取订单详情失败，将使用兜底匹配")
                except Exception as e:
                    logger.error(f"获取订单规格信息失败: {self._safe_str(e)}，将使用兜底匹配")

            # 重新匹配发货规则（考虑规格信息）
            if has_multi_spec_rules and spec_name and spec_value:
                # 尝试精确匹配多规格发货规则
                multi_spec_rules = [rule for rule in delivery_rules 
                                  if rule.get('rule_is_multi_spec') 
                                  and rule.get('rule_spec_name') == spec_name 
                                  and rule.get('rule_spec_value') == spec_value]
                if multi_spec_rules:
                    delivery_rules = multi_spec_rules
                    logger.info(f"🎯 使用精确匹配的多规格发货规则: {len(delivery_rules)}个")
                else:
                    # 使用普通规则作为兜底
                    delivery_rules = [rule for rule in delivery_rules if not rule.get('rule_is_multi_spec')]
                    logger.info(f"🔄 多规格精确匹配失败，使用普通发货规则兜底: {len(delivery_rules)}个")
            
            if not delivery_rules:
                logger.debug(f"未找到可用的发货规则")
                return None

            # 使用第一个匹配的规则（按关键字长度降序排列，优先匹配更精确的规则）
            rule = delivery_rules[0]

            # 保存商品信息到数据库（需要有商品标题才保存）
            # 尝试获取商品标题
            item_title_for_save = None
            try:
                from db_manager import db_manager
                db_item_info = db_manager.get_item_info(self.cookie_id, item_id)
                if db_item_info:
                    item_title_for_save = db_item_info.get('item_title', '').strip()
            except:
                pass

            # 如果有商品标题，则保存商品信息
            if item_title_for_save:
                await self.save_item_info_to_db(item_id, search_text, item_title_for_save)
            else:
                logger.debug(f"跳过保存商品信息：缺少商品标题 - {item_id}")

            # 详细的匹配结果日志
            if rule.get('is_multi_spec'):
                if spec_name and spec_value:
                    # 安全地处理规则信息，避免编码问题
                    safe_item_id = self._safe_encode_data(rule.get('item_id', 'unknown'))
                    safe_card_name = self._safe_encode_data(rule.get('card_name', 'unknown'))
                    safe_spec_name = self._safe_encode_data(rule.get('spec_name', 'unknown'))
                    safe_spec_value = self._safe_encode_data(rule.get('spec_value', 'unknown'))
                    safe_order_spec_name = self._safe_encode_data(spec_name)
                    safe_order_spec_value = self._safe_encode_data(spec_value)
                    logger.info(f"🎯 精确匹配多规格发货规则: {safe_item_id} -> {safe_card_name} [{safe_spec_name}:{safe_spec_value}]")
                    logger.info(f"📋 订单规格: {safe_order_spec_name}:{safe_order_spec_value} ✅ 匹配卡券规格: {safe_spec_name}:{safe_spec_value}")
                else:
                    # 安全地处理规则信息，避免编码问题
                    safe_item_id = self._safe_encode_data(rule.get('item_id', 'unknown'))
                    safe_card_name = self._safe_encode_data(rule.get('card_name', 'unknown'))
                    safe_spec_name = self._safe_encode_data(rule.get('spec_name', 'unknown'))
                    safe_spec_value = self._safe_encode_data(rule.get('spec_value', 'unknown'))
                    logger.info(f"⚠️ 使用多规格发货规则但无订单规格信息: {safe_item_id} -> {safe_card_name} [{safe_spec_name}:{safe_spec_value}]")
            else:
                if spec_name and spec_value:
                    # 安全地处理规则信息，避免编码问题
                    safe_item_id = self._safe_encode_data(rule.get('item_id', 'unknown'))
                    safe_card_name = self._safe_encode_data(rule.get('card_name', 'unknown'))
                    safe_card_type = self._safe_encode_data(rule.get('card_type', 'unknown'))
                    safe_order_spec_name = self._safe_encode_data(spec_name)
                    safe_order_spec_value = self._safe_encode_data(spec_value)
                    logger.info(f"🔄 兜底匹配普通发货规则: {safe_item_id} -> {safe_card_name} ({safe_card_type})")
                    logger.info(f"📋 订单规格: {safe_order_spec_name}:{safe_order_spec_value} ➡️ 使用普通卡券兜底")
                else:
                    # 安全地处理规则信息，避免编码问题
                    safe_item_id = self._safe_encode_data(rule.get('item_id', 'unknown'))
                    safe_card_name = self._safe_encode_data(rule.get('card_name', 'unknown'))
                    safe_card_type = self._safe_encode_data(rule.get('card_type', 'unknown'))
                    logger.info(f"✅ 匹配普通发货规则: {safe_item_id} -> {safe_card_name} ({safe_card_type})")

            # 获取延时设置
            delay_seconds = rule.get('card_delay_seconds', 0)

            # 执行延时（不管是否确认发货，只要有延时设置就执行）
            if delay_seconds and delay_seconds > 0:
                logger.info(f"检测到发货延时设置: {delay_seconds}秒，开始延时...")
                await asyncio.sleep(delay_seconds)
                logger.info(f"延时完成")

            # 如果有订单ID，执行确认发货
            if order_id:
                # 检查是否启用自动确认发货
                if not self.is_auto_confirm_enabled():
                    logger.info(f"自动确认发货已关闭，跳过订单 {order_id}")
                else:
                    # 检查确认发货冷却时间
                    current_time = time.time()
                    should_confirm = True

                    if order_id in self.confirmed_orders:
                        last_confirm_time = self.confirmed_orders[order_id]
                        if current_time - last_confirm_time < self.order_confirm_cooldown:
                            logger.info(f"订单 {order_id} 已在 {self.order_confirm_cooldown} 秒内确认过，跳过重复确认")
                            should_confirm = False

                    if should_confirm:
                        logger.info(f"开始自动确认发货: 订单ID={order_id}")
                        confirm_result = await self.auto_confirm(order_id, item_id)
                        if confirm_result.get('success'):
                            self.confirmed_orders[order_id] = current_time
                            logger.info(f"🎉 自动确认发货成功！订单ID: {order_id}")
                        else:
                            logger.warning(f"⚠️ 自动确认发货失败: {confirm_result.get('error', '未知错误')}")
                            # 即使确认发货失败，也继续发送发货内容

            # 检查是否存在订单ID，只有存在订单ID才处理发货内容
            if order_id:
                # 开始处理发货内容
                # 安全地处理规则信息，避免编码问题
                safe_item_id = self._safe_encode_data(rule.get('item_id', 'unknown'))
                safe_card_name = self._safe_encode_data(rule.get('card_name', 'unknown'))
                safe_card_type = self._safe_encode_data(rule.get('card_type', 'unknown'))
                logger.info(f"开始处理发货内容，规则: {safe_item_id} -> {safe_card_name} ({safe_card_type})")

                delivery_content = None

                # 根据卡券类型处理发货内容
                if rule['card_type'] == 'api':
                    # API类型：此方法不应处理API卡券，应该在_handle_auto_delivery中处理
                    logger.error("❌ _auto_delivery方法不应处理API类型卡券")
                    return None

                elif rule['card_type'] == 'text':
                    # 固定文字类型：直接使用文字内容
                    delivery_content = rule['text_content']

                elif rule['card_type'] == 'data':
                    # 批量数据类型：先获取第一条数据但不消费，返回特殊标记
                    # 实际消费将在发送成功后进行
                    card_data = self._peek_batch_data(rule['card_id'])
                    if card_data:
                        delivery_content = f"__BATCH_DATA__{rule['card_id']}|{card_data}"
                    else:
                        # 找到了规则但没有库存，返回特殊标记
                        logger.warning(f"找到发货规则但卡券无库存: 规则ID={rule['id']}, 卡券ID={rule['card_id']}")
                        return "__NO_STOCK__"
                    
                    # 检查是否需要生成图片（不再限制为12位数字）
                    if delivery_content and delivery_content.startswith("__BATCH_DATA__"):
                        # 提取实际的卡密数据
                        parts = delivery_content.replace("__BATCH_DATA__", "").split("|", 1)
                        if len(parts) == 2:
                            card_id_str, actual_data = parts
                            # 检查是否需要生成图片
                            generate_image = rule.get('generate_image', True)  # 默认为True
                            logger.info(f"检测到卡密: {actual_data}，生成图片设置: {generate_image}")
                            
                            if generate_image:
                                logger.info(f"开始生成卡密图片: {actual_data}")
                                try:
                                    # 安全地处理actual_data，确保编码正确
                                    safe_actual_data = self._safe_encode_data(actual_data)
                                    logger.info(f"安全处理后的卡密数据: {safe_actual_data}")
                                    
                                    # 调用gm_main生成图片
                                    from GenerateCoupon import gm_main
                                    image_path = gm_main(safe_actual_data)
                                    
                                    if image_path and os.path.exists(image_path):
                                        # 移动图片到uploads目录
                                        import shutil
                                        upload_dir = "static/uploads"
                                        os.makedirs(upload_dir, exist_ok=True)
                                        
                                        # 生成新的文件名
                                        import uuid
                                        file_extension = os.path.splitext(image_path)[1]
                                        new_filename = f"coupon_{uuid.uuid4().hex[:8]}{file_extension}"
                                        new_image_path = os.path.join(upload_dir, new_filename)
                                        
                                        # 移动文件
                                        shutil.move(image_path, new_image_path)
                                        
                                        # 标准化路径格式（使用正斜杠）
                                        normalized_path = new_image_path.replace('\\', '/')
                                        
                                        # 检查是否有备注信息，决定使用哪种格式
                                        card_description = rule.get('card_description', '')
                                        if card_description and card_description.strip():
                                            # 有备注信息，使用新格式支持分离发送
                                            delivery_content = f"__BATCH_DATA_IMAGE_WITH_NOTE__{rule['card_id']}|{normalized_path}|{actual_data}|{card_description}"
                                            safe_path = self._safe_encode_data(normalized_path)
                                            logger.info(f"卡密图片生成成功(含备注): {safe_path}")
                                        else:
                                            # 无备注信息，使用原有格式
                                            delivery_content = f"__BATCH_DATA_IMAGE__{rule['card_id']}|{normalized_path}|{actual_data}"
                                            safe_path = self._safe_encode_data(normalized_path)
                                            logger.info(f"卡密图片生成成功: {safe_path}")
                                    else:
                                        safe_image_path = self._safe_encode_data(image_path) if image_path else "None"
                                        logger.error(f"图片生成失败或文件不存在: {safe_image_path}")
                                        # 如果图片生成失败，保持原始的批量数据标记
                                        logger.info(f"图片生成失败，保持原始批量数据标记")
                                except Exception as e:
                                    logger.error(f"生成卡密图片失败: {self._safe_str(e)}")
                                    # 如果出现异常，保持原始的批量数据标记
                                    logger.info(f"图片生成异常，保持原始批量数据标记")
                            else:
                                # 不生成图片，直接返回券码文本
                                logger.info(f"根据设置不生成图片，直接返回券码文本: {actual_data}")
                                # 保持原始的批量数据标记，但在后续处理中会作为文本发送

                elif rule['card_type'] == 'image':
                    # 图片类型：返回图片发送标记，包含卡券ID和备注信息
                    image_url = rule.get('image_url')
                    card_description = rule.get('card_description', '')
                    if image_url:
                        # 如果有备注信息，使用新的格式包含备注
                        if card_description and card_description.strip():
                            delivery_content = f"__IMAGE_WITH_NOTE__{rule['card_id']}|{image_url}|{card_description}"
                            safe_image_url = self._safe_encode_data(image_url)
                            safe_card_description = self._safe_encode_data(card_description)
                            logger.info(f"准备发送图片和备注: {safe_image_url} (卡券ID: {rule['card_id']}, 备注: {safe_card_description})")
                        else:
                            delivery_content = f"__IMAGE_SEND__{rule['card_id']}|{image_url}"
                            safe_image_url = self._safe_encode_data(image_url)
                            logger.info(f"准备发送图片: {safe_image_url} (卡券ID: {rule['card_id']})")
                    else:
                        logger.error(f"图片卡券缺少图片URL: 卡券ID={rule['card_id']}")
                        delivery_content = None

                if delivery_content:
                    # 对于使用新格式的内容，不再进行备注处理
                    if (rule['card_type'] == 'image' and delivery_content.startswith("__IMAGE_WITH_NOTE__")) or \
                       delivery_content.startswith("__BATCH_DATA_IMAGE_WITH_NOTE__"):
                        final_content = delivery_content
                    else:
                        # 处理备注信息和变量替换
                        final_content = self._process_delivery_content_with_description(delivery_content, rule.get('card_description', ''))

                    # 自动发货成功，先检查并扣除聚合豆（10聚合豆）
                    user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
                    
                    if user_id:
                        # 检查余额并扣费（自动发货成功扣除10聚合豆）
                        balance_sufficient = db_manager.check_and_consume_balance(
                            user_id=user_id,
                            amount=10.0,
                            description=f"自动发货 - 商品ID:{item_id}, 规则ID:{rule['id']}",
                            order_id=order_id
                        )
                        
                        if not balance_sufficient:
                            logger.warning(f"【{self.cookie_id}】用户余额不足，无法扣除自动发货费用，取消发货")
                            return None
                    else:
                        logger.error(f"【{self.cookie_id}】无法获取用户ID，取消自动发货")
                        return None
                    
                    # 增加发货次数统计
                    db_manager.increment_delivery_times(rule['id'])
                    logger.info(f"自动发货成功: 规则ID={rule['id']}, 内容长度={len(final_content)}, 已扣除10聚合豆")
                    return final_content
                else:
                    logger.warning(f"获取发货内容失败: 规则ID={rule['id']}")
                    # 这里是其他类型的发货内容获取失败，不是库存问题
                    return None
            else:
                # 没有订单ID，记录日志但不处理发货内容
                # 安全地处理规则信息，避免编码问题
                safe_item_id = self._safe_encode_data(rule.get('item_id', 'unknown'))
                safe_card_name = self._safe_encode_data(rule.get('card_name', 'unknown'))
                safe_card_type = self._safe_encode_data(rule.get('card_type', 'unknown'))
                logger.info(f"⚠️ 未检测到订单ID，跳过发货内容处理。规则: {safe_item_id} -> {safe_card_name} ({safe_card_type})")
                return None

        except Exception as e:
            logger.error(f"自动发货失败: {self._safe_str(e)}")
            return None

    def _process_delivery_content_with_description(self, delivery_content: str, card_description: str) -> str:
        """处理发货内容和备注信息，实现变量替换"""
        try:
            # 如果没有备注信息，直接返回发货内容
            if not card_description or not card_description.strip():
                return delivery_content

            # 替换备注中的变量
            processed_description = card_description.replace('{DELIVERY_CONTENT}', delivery_content)

            # 如果备注中包含变量替换，返回处理后的备注
            if '{DELIVERY_CONTENT}' in card_description:
                return processed_description
            else:
                # 如果备注中没有变量，将备注和发货内容组合
                return f"{processed_description}\n\n{delivery_content}"

        except Exception as e:
            logger.error(f"处理备注信息失败: {e}")
            # 出错时返回原始发货内容
            return delivery_content

    async def _get_api_card_content(self, rule, order_id=None, quantity=1, retry_count=0):
        """调用JH API获取卡券内容，支持3次重试机制"""
        max_retries = 3

        if retry_count >= max_retries:
            logger.error(f"JH API调用失败，已达到最大重试次数({max_retries})")
            return None, 0  # 返回元组 (coupon_list, total_cost)

        try:
            api_config = rule.get('api_config')
            if not api_config:
                logger.error(f"API配置为空，规则ID: {rule.get('id')}, 卡券名称: {rule.get('card_name')}")
                return None, 0

            # 解析API配置
            if isinstance(api_config, str):
                api_config = json.loads(api_config)

            coupon_seed_id = api_config.get('couponSeedId')
            companysk = api_config.get('companysk')
            
            # 兼容性处理：如果没有companysk但有旧的companyId，提示用户更新配置
            if not companysk and api_config.get('companyId'):
                logger.error(f"检测到旧的companyId配置，请更新为companysk配置。卡种ID: {coupon_seed_id}")
                return None, 0
            
            if not coupon_seed_id or not companysk:
                logger.error(f"API配置缺少必要参数: couponSeedId={coupon_seed_id}, companysk={'已配置' if companysk else '未配置'}")
                return None, 0

            retry_info = f" (重试 {retry_count + 1}/{max_retries})" if retry_count > 0 else ""
            logger.info(f"调用JH API获取卡券{retry_info}: couponSeedId={coupon_seed_id}, orderNo={order_id}, quantity={quantity}")

            # 调用JH API
            from JHAPI import get_coupon_list
            coupon_list, code, cost = get_coupon_list(coupon_seed_id, order_id or "", quantity, companysk)

            if code == 200 and coupon_list:
                logger.info(f"JH API调用成功，获取到 {len(coupon_list)} 张卡券，总成本: {cost}")
                return coupon_list, cost
            elif code == 401:
                # 签名验证失败，检查companysk是否正确
                logger.warning("JH API签名验证失败，请检查companysk是否正确")
                logger.error(f"JH API签名验证失败: code={code}")
                
                # 如果是第一次失败，进行重试
                if retry_count < max_retries - 1:
                    logger.info(f"JH API签名验证失败，将进行第 {retry_count + 2} 次重试")
                    await asyncio.sleep(1)  # 等待1秒后重试
                    return await self._get_api_card_content(rule, order_id, quantity, retry_count + 1)
                else:
                    # 重试失败，发送微信通知
                    await self._send_api_failure_notification(
                        coupon_seed_id, code, order_id, 
                        f"JH API签名验证失败，卡种ID: {coupon_seed_id}，请检查companysk配置，错误代码: {code}"
                    )
                return None, 0
            elif code == 403:
                # 权限错误，进行重试
                logger.error(f"JH API调用权限错误: code={code}")
                
                # 如果是第一次失败，进行重试
                if retry_count < max_retries - 1:
                    logger.info(f"JH API权限错误，将进行第 {retry_count + 2} 次重试")
                    await asyncio.sleep(1)  # 等待1秒后重试
                    return await self._get_api_card_content(rule, order_id, quantity, retry_count + 1)
                else:
                    # 重试失败，发送微信通知
                    await self._send_api_failure_notification(
                        coupon_seed_id, code, order_id,
                        f"JH API调用权限错误，卡种ID: {coupon_seed_id}，错误代码: {code}"
                    )
                return None, 0
            else:
                # 其他错误，进行重试
                logger.warning(f"JH API调用失败: code={code}, coupon_list={coupon_list}")
                
                # 如果是第一次失败，进行重试
                if retry_count < max_retries - 1:
                    logger.info(f"JH API调用失败，将进行第 {retry_count + 2} 次重试")
                    await asyncio.sleep(1)  # 等待1秒后重试
                    return await self._get_api_card_content(rule, order_id, quantity, retry_count + 1)
                else:
                    # 重试失败，发送微信通知
                    await self._send_api_failure_notification(
                        coupon_seed_id, code, order_id,
                        f"JH API调用失败，卡种ID: {coupon_seed_id}，错误代码: {code}"
                    )
                return None, 0

        except Exception as e:
            logger.error(f"JH API调用异常: {self._safe_str(e)}")
            
            # 如果是异常且还有重试机会，进行重试
            if retry_count < max_retries - 1:
                logger.info(f"JH API调用异常，将进行第 {retry_count + 2} 次重试")
                await asyncio.sleep(1)  # 等待1秒后重试
                return await self._get_api_card_content(rule, order_id, quantity, retry_count + 1)
            else:
                # 重试失败，发送微信通知
                await self._send_api_failure_notification(
                    api_config.get('couponSeedId') if api_config else "未知", 
                    "异常", order_id,
                    f"JH API调用异常: {self._safe_str(e)}"
                )
            return None, 0

    async def _send_api_failure_notification(self, coupon_seed_id, error_code, order_id, error_message):
        """发送API调用失败的微信群通知"""
        try:
            from db_manager import db_manager
            import time
            
            # 获取当前账号的通知配置
            notifications = db_manager.get_message_notifications(self.cookie_id)
            
            if not notifications:
                logger.debug(f"账号 {self.cookie_id} 未配置通知渠道，无法发送API失败通知")
                return
            
            # 获取账号备注信息
            cookie_details = db_manager.get_cookie_details(self.cookie_id)
            account_remark = cookie_details.get('remark', '') if cookie_details else ''
            
            # 获取get_coupon_list的response.text
            response_text = ""
            try:
                from JHAPI import get_last_response_text
                # 获取最后一次API调用的响应文本
                response_text = get_last_response_text()
                if not response_text:
                    response_text = "无响应内容"
            except Exception as e:
                response_text = f"无法获取响应详情: {str(e)}"
            
            # 构建通知消息
            notification_msg = f"🚨 JH API调用失败通知\n\n" \
                             f"账号: {self.cookie_id}\n"
            
            # 如果有备注，添加到通知消息中
            if account_remark:
                notification_msg += f"备注: {account_remark}\n"
            
            notification_msg += f"卡种ID: {coupon_seed_id}\n" \
                              f"订单ID: {order_id or '未知'}\n" \
                              f"错误代码: {error_code}\n" \
                              f"错误信息: {error_message}\n" \
                              f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n" \
                              f"API响应详情:\n{response_text}\n"
            
            # 发送通知到各个渠道
            notification_sent = False
            for notification in notifications:
                if not notification.get('enabled', True):
                    continue
                
                channel_type = notification.get('channel_type')
                channel_config = notification.get('config')
                
                if channel_config:
                    try:
                        config_data = json.loads(channel_config)
                    except:
                        config_data = {}
                    
                    if channel_type == 'webhook':
                        await self._send_webhook_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'wechat':
                        await self._send_wechat_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type in ['ding_talk', 'dingtalk']:
                        await self._send_dingtalk_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'email':
                        await self._send_email_notification(config_data, notification_msg)
                        notification_sent = True
                    elif channel_type == 'telegram':
                        await self._send_telegram_notification(config_data, notification_msg)
                        notification_sent = True
            
            if notification_sent:
                logger.info(f"【{self.cookie_id}】JH API失败通知发送成功")
            else:
                logger.warning(f"【{self.cookie_id}】JH API失败通知发送失败，没有可用的通知渠道")
                
        except Exception as e:
            logger.error(f"发送JH API失败通知异常: {self._safe_str(e)}")

    async def create_chat(self, ws, toid, item_id='891198795482'):
        msg = {
            "lwp": "/r/SingleChatConversation/create",
            "headers": {
                "mid": generate_mid()
            },
            "body": [
                {
                    "pairFirst": f"{toid}@goofish",
                    "pairSecond": f"{self.myid}@goofish",
                    "bizType": "1",
                    "extension": {
                        "itemId": item_id
                    },
                    "ctx": {
                        "appVersion": "1.0",
                        "platform": "web"
                    }
                }
            ]
        }
        await ws.send(json.dumps(msg))

    async def send_msg(self, ws, cid, toid, text):
        """发送消息给客户，带重试机制"""
        return await self._send_msg_with_retry(ws, cid, toid, text)
    
    async def _send_msg_with_retry(self, ws, cid, toid, text, max_retries=None, retry_delay=None):
        """
        发送消息给客户，带重试机制
        :param ws: WebSocket连接
        :param cid: 聊天ID
        :param toid: 目标用户ID
        :param text: 消息内容
        :param max_retries: 最大重试次数，None时从配置读取
        :param retry_delay: 重试间隔，None时从配置读取
        :return: 是否发送成功
        """
        # 从配置文件读取重试参数
        if max_retries is None or retry_delay is None:
            try:
                from config import config
                retry_config = config.get('WEBSOCKET_MESSAGE_RETRY', {})
                if max_retries is None:
                    max_retries = retry_config.get('max_retries', 3)
                if retry_delay is None:
                    retry_delay = retry_config.get('retry_delay', 5)
                
                # 检查是否启用重试
                if not retry_config.get('enabled', True):
                    max_retries = 0  # 禁用重试
                    
            except Exception as e:
                logger.warning(f"【{self.cookie_id}】读取重试配置失败，使用默认值: {e}")
                if max_retries is None:
                    max_retries = 3
                if retry_delay is None:
                    retry_delay = 5
        text_data = {
            "contentType": 1,
            "text": {
                "text": text
            }
        }
        text_base64 = str(base64.b64encode(json.dumps(text_data).encode('utf-8')), 'utf-8')
        msg = {
            "lwp": "/r/MessageSend/sendByReceiverScope",
            "headers": {
                "mid": generate_mid()
            },
            "body": [
                {
                    "uuid": generate_uuid(),
                    "cid": f"{cid}@goofish",
                    "conversationType": 1,
                    "content": {
                        "contentType": 101,
                        "custom": {
                            "type": 1,
                            "data": text_base64
                        }
                    },
                    "redPointPolicy": 0,
                    "extension": {
                        "extJson": "{}"
                    },
                    "ctx": {
                        "appVersion": "1.0",
                        "platform": "web"
                    },
                    "mtags": {},
                    "msgReadStatusSetting": 1
                },
                {
                    "actualReceivers": [
                        f"{toid}@goofish",
                        f"{self.myid}@goofish"
                    ]
                }
            ]
        }
        
        # 尝试发送消息，带重试机制
        for attempt in range(max_retries + 1):  # 包括首次尝试，总共max_retries+1次
            try:
                await ws.send(json.dumps(msg))
                if attempt > 0:
                    logger.info(f"【{self.cookie_id}】消息发送成功（第{attempt+1}次尝试）: 用户ID {toid}")
                return True
                
            except Exception as e:
                if attempt < max_retries:
                    logger.warning(f"【{self.cookie_id}】消息发送失败（第{attempt+1}次尝试），{retry_delay}秒后重试: {self._safe_str(e)}")
                    await asyncio.sleep(retry_delay)
                    
                    # 检查WebSocket连接状态，如果断开了可能已经重连
                    if hasattr(ws, 'closed') and ws.closed:
                        logger.info(f"【{self.cookie_id}】WebSocket连接已断开，等待重连...")
                        # 这里可以添加等待重连的逻辑，或者直接继续重试
                        
                else:
                    logger.error(f"【{self.cookie_id}】消息发送最终失败，已重试{max_retries}次: 用户ID {toid}, 消息: {text[:50]}{'...' if len(text) > 50 else ''}")
                    return False
                    
        return False
    
    async def _send_image_msg_with_retry(self, ws, msg, toid, image_url, max_retries=None, retry_delay=None):
        """
        发送图片消息，带重试机制
        :param ws: WebSocket连接
        :param msg: 图片消息数据
        :param toid: 目标用户ID
        :param image_url: 图片URL
        :param max_retries: 最大重试次数，None时从配置读取
        :param retry_delay: 重试间隔，None时从配置读取
        :return: 是否发送成功
        """
        # 从配置文件读取重试参数
        if max_retries is None or retry_delay is None:
            try:
                from config import config
                retry_config = config.get('WEBSOCKET_MESSAGE_RETRY', {})
                if max_retries is None:
                    max_retries = retry_config.get('max_retries', 3)
                if retry_delay is None:
                    retry_delay = retry_config.get('retry_delay', 5)
                
                # 检查是否启用重试
                if not retry_config.get('enabled', True):
                    max_retries = 0  # 禁用重试
                    
            except Exception as e:
                logger.warning(f"【{self.cookie_id}】读取重试配置失败，使用默认值: {e}")
                if max_retries is None:
                    max_retries = 3
                if retry_delay is None:
                    retry_delay = 5
        # 尝试发送图片消息，带重试机制
        for attempt in range(max_retries + 1):  # 包括首次尝试，总共max_retries+1次
            try:
                await ws.send(json.dumps(msg))
                if attempt > 0:
                    logger.info(f"【{self.cookie_id}】图片消息发送成功（第{attempt+1}次尝试）: 用户ID {toid}")
                else:
                    logger.info(f"【{self.cookie_id}】图片消息发送成功: {image_url}")
                return True
                
            except Exception as e:
                if attempt < max_retries:
                    logger.warning(f"【{self.cookie_id}】图片消息发送失败（第{attempt+1}次尝试），{retry_delay}秒后重试: {self._safe_str(e)}")
                    await asyncio.sleep(retry_delay)
                    
                    # 检查WebSocket连接状态，如果断开了可能已经重连
                    if hasattr(ws, 'closed') and ws.closed:
                        logger.info(f"【{self.cookie_id}】WebSocket连接已断开，等待重连...")
                        
                else:
                    logger.error(f"【{self.cookie_id}】图片消息发送最终失败，已重试{max_retries}次: 用户ID {toid}, 图片URL: {image_url}")
                    return False
                    
        return False

    async def init(self, ws):
        # 如果没有token，获取新token
        token_refresh_attempted = False
        if not self.current_token:
            logger.info(f"【{self.cookie_id}】获取初始token...")
            token_refresh_attempted = True
            await self.refresh_token(skip_restart=True)

        if not self.current_token:
            logger.error("无法获取有效token，初始化失败")

            # 只有在确实尝试过Token刷新后才更新Token状态为失效
            if token_refresh_attempted:
                from db_manager import db_manager
                import datetime
                current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                db_manager.update_token_status(self.cookie_id, 'invalid', current_time)
                logger.warning(f"【{self.cookie_id}】Token刷新失败，已更新Token状态为失效")
            else:
                logger.info(f"【{self.cookie_id}】初始化失败但未尝试Token刷新，保持当前Token状态")
            
            # 只有在没有尝试刷新token的情况下才发送通知，避免与refresh_token中的通知重复
            if not token_refresh_attempted:
                await self.send_token_refresh_notification("初始化时无法获取有效Token", "token_init_failed")
            else:
                logger.info("由于刚刚尝试过token刷新，跳过重复的初始化失败通知")
            raise Exception("Token获取失败")
            
        msg = {
            "lwp": "/reg",
            "headers": {
                "cache-header": "app-key token ua wv",
                "app-key": APP_CONFIG.get('app_key'),
                "token": self.current_token,
                "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 DingTalk(2.1.5) OS(Windows/10) Browser(Chrome/133.0.0.0) DingWeb/2.1.5 IMPaaS DingWeb/2.1.5",
                "dt": "j",
                "wv": "im:3,au:3,sy:6",
                "sync": "0,0;0;0;",
                "did": self.device_id,
                "mid": generate_mid()
            }
        }
        await ws.send(json.dumps(msg))
        await asyncio.sleep(1)
        current_time = int(time.time() * 1000)
        msg = {
            "lwp": "/r/SyncStatus/ackDiff",
            "headers": {"mid": generate_mid()},
            "body": [
                {
                    "pipeline": "sync",
                    "tooLong2Tag": "PNM,1",
                    "channel": "sync",
                    "topic": "sync",
                    "highPts": 0,
                    "pts": current_time * 1000,
                    "seq": 0,
                    "timestamp": current_time
                }
            ]
        }
        await ws.send(json.dumps(msg))
        logger.info(f'【{self.cookie_id}】连接注册完成')

    async def send_heartbeat(self, ws):
        """发送心跳包"""
        msg = {
            "lwp": "/!",
            "headers": {
                "mid": generate_mid()
            }
        }
        await ws.send(json.dumps(msg))
        self.last_heartbeat_time = time.time()

    async def heartbeat_loop(self, ws):
        """心跳循环"""
        while True:
            try:
                # 检查账号是否启用
                from cookie_manager import manager as cookie_manager
                if cookie_manager and not cookie_manager.get_cookie_status(self.cookie_id):
                    logger.info(f"【{self.cookie_id}】账号已禁用，停止心跳循环")
                    break

                await self.send_heartbeat(ws)
                await asyncio.sleep(self.heartbeat_interval)
            except Exception as e:
                logger.error(f"心跳发送失败: {self._safe_str(e)}")
                break

    async def handle_heartbeat_response(self, message_data):
        """处理心跳响应"""
        try:
            if message_data.get("code") == 200:
                self.last_heartbeat_response = time.time()
                logger.debug("心跳响应正常")
                return True
        except Exception as e:
            logger.error(f"处理心跳响应出错: {self._safe_str(e)}")
        return False

    async def pause_cleanup_loop(self):
        """定期清理过期的暂停记录"""
        while True:
            try:
                # 检查账号是否启用
                from cookie_manager import manager as cookie_manager
                if cookie_manager and not cookie_manager.get_cookie_status(self.cookie_id):
                    logger.info(f"【{self.cookie_id}】账号已禁用，停止暂停记录清理循环")
                    break

                # 清理过期的暂停记录
                pause_manager.cleanup_expired_pauses()

                # 每5分钟清理一次
                await asyncio.sleep(300)
            except Exception as e:
                logger.error(f"【{self.cookie_id}】暂停记录清理失败: {self._safe_str(e)}")
                await asyncio.sleep(300)  # 出错后也等待5分钟再重试

    async def send_msg_once(self, toid, item_id, text):
        headers = {
            "Cookie": self.cookies_str,
            "Host": "wss-goofish.dingtalk.com",
            "Connection": "Upgrade",
            "Pragma": "no-cache",
            "Cache-Control": "no-cache",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
            "Origin": "https://www.goofish.com",
            "Accept-Encoding": "gzip, deflate, br, zstd",
            "Accept-Language": "zh-CN,zh;q=0.9",
        }
        # 兼容不同版本的websockets库
        try:
            async with websockets.connect(
                self.base_url,
                extra_headers=headers
            ) as websocket:
                await self._handle_websocket_connection(websocket, toid, item_id, text)
        except TypeError as e:
            # 安全地检查异常信息
            error_msg = self._safe_str(e)

            if "extra_headers" in error_msg:
                logger.warning("websockets库不支持extra_headers参数，使用兼容模式")
                # 使用兼容模式，通过subprotocols传递部分头信息
                async with websockets.connect(
                    self.base_url,
                    additional_headers=headers
                ) as websocket:
                    await self._handle_websocket_connection(websocket, toid, item_id, text)
            else:
                raise

    async def _create_websocket_connection(self, headers):
        """创建WebSocket连接，兼容不同版本的websockets库"""
        import websockets

        # 获取websockets版本用于调试
        websockets_version = getattr(websockets, '__version__', '未知')
        logger.debug(f"websockets库版本: {websockets_version}")

        try:
            # 尝试使用extra_headers参数
            return websockets.connect(
                self.base_url,
                extra_headers=headers
            )
        except Exception as e:
            # 捕获所有异常类型，不仅仅是TypeError
            error_msg = self._safe_str(e)
            logger.debug(f"extra_headers参数失败: {error_msg}")

            if "extra_headers" in error_msg or "unexpected keyword argument" in error_msg:
                logger.warning("websockets库不支持extra_headers参数，尝试additional_headers")
                # 使用additional_headers参数（较新版本）
                try:
                    return websockets.connect(
                        self.base_url,
                        additional_headers=headers
                    )
                except Exception as e2:
                    error_msg2 = self._safe_str(e2)
                    logger.debug(f"additional_headers参数失败: {error_msg2}")

                    if "additional_headers" in error_msg2 or "unexpected keyword argument" in error_msg2:
                        # 如果都不支持，则不传递headers
                        logger.warning("websockets库不支持headers参数，使用基础连接模式")
                        return websockets.connect(self.base_url)
                    else:
                        raise e2
            else:
                raise e

    async def _handle_websocket_connection(self, websocket, toid, item_id, text):
        """处理WebSocket连接的具体逻辑"""
        await self.init(websocket)
        await self.create_chat(websocket, toid, item_id)
        async for message in websocket:
            try:
                logger.info(f"【{self.cookie_id}】message: {message}")
                message = json.loads(message)
                cid = message["body"]["singleChatConversation"]["cid"]
                cid = cid.split('@')[0]
                await self.send_msg(websocket, cid, toid, text)
                logger.info(f'【{self.cookie_id}】send message')
                return
            except Exception as e:
                pass

    def is_chat_message(self, message):
        """判断是否为用户聊天消息"""
        try:
            return (
                isinstance(message, dict) 
                and "1" in message 
                and isinstance(message["1"], dict)
                and "10" in message["1"]
                and isinstance(message["1"]["10"], dict)
                and "reminderContent" in message["1"]["10"]
            )
        except Exception:
            return False

    def is_sync_package(self, message_data):
        """判断是否为同步包消息"""
        try:
            return (
                isinstance(message_data, dict)
                and "body" in message_data
                and "syncPushPackage" in message_data["body"]
                and "data" in message_data["body"]["syncPushPackage"]
                and len(message_data["body"]["syncPushPackage"]["data"]) > 0
            )
        except Exception:
            return False

    async def create_session(self):
        """创建aiohttp session"""
        if not self.session:
            # 创建带有cookies和headers的session
            headers = DEFAULT_HEADERS.copy()
            headers['cookie'] = self.cookies_str

            self.session = aiohttp.ClientSession(
                headers=headers,
                timeout=aiohttp.ClientTimeout(total=30)
            )

    async def close_session(self):
        """关闭aiohttp session"""
        if self.session:
            await self.session.close()
            self.session = None

    async def get_api_reply(self, msg_time, user_url, send_user_id, send_user_name, item_id, send_message, chat_id):
        """调用API获取回复消息"""
        try:
            if not self.session:
                await self.create_session()

            api_config = AUTO_REPLY.get('api', {})
            timeout = aiohttp.ClientTimeout(total=api_config.get('timeout', 10))
            
            payload = {
                "cookie_id": self.cookie_id,
                "msg_time": msg_time,
                "user_url": user_url,
                "send_user_id": send_user_id,
                "send_user_name": send_user_name,
                "item_id": item_id,
                "send_message": send_message,
                "chat_id": chat_id
            }
            
            async with self.session.post(
                api_config.get('url', 'http://localhost:10086/xianyu/reply'),
                json=payload,
                timeout=timeout
            ) as response:
                result = await response.json()
                
                # 将code转换为字符串进行比较，或者直接用数字比较
                if str(result.get('code')) == '200' or result.get('code') == 200:
                    send_msg = result.get('data', {}).get('send_msg')
                    if send_msg:
                        # 格式化消息中的占位符
                        return send_msg.format(
                            send_user_id=payload['send_user_id'],
                            send_user_name=payload['send_user_name'],
                            send_message=payload['send_message']
                        )
                    else:
                        logger.warning("API返回成功但无回复消息")
                        return None
                else:
                    logger.warning(f"API返回错误: {result.get('msg', '未知错误')}")
                    return None
                    
        except asyncio.TimeoutError:
            logger.error("API调用超时")
            return None
        except Exception as e:
            logger.error(f"调用API出错: {self._safe_str(e)}")
            return None

    async def handle_message(self, message_data, websocket):
        """处理所有类型的消息"""
        try:
            # 检查账号是否启用
            from cookie_manager import manager as cookie_manager
            if cookie_manager and not cookie_manager.get_cookie_status(self.cookie_id):
                logger.debug(f"【{self.cookie_id}】账号已禁用，跳过消息处理")
                return

            # 发送确认消息
            try:
                message = message_data
                ack = {
                    "code": 200,
                    "headers": {
                        "mid": message["headers"]["mid"] if "mid" in message["headers"] else generate_mid(),
                        "sid": message["headers"]["sid"] if "sid" in message["headers"] else '',
                    }
                }
                if 'app-key' in message["headers"]:
                    ack["headers"]["app-key"] = message["headers"]["app-key"]
                if 'ua' in message["headers"]:
                    ack["headers"]["ua"] = message["headers"]["ua"]
                if 'dt' in message["headers"]:
                    ack["headers"]["dt"] = message["headers"]["dt"]
                await websocket.send(json.dumps(ack))
            except Exception as e:
                pass

            # 如果不是同步包消息，直接返回
            if not self.is_sync_package(message_data):
                return

            # 获取并解密数据
            sync_data = message_data["body"]["syncPushPackage"]["data"][0]
            
            # 检查是否有必要的字段
            if "data" not in sync_data:
                logger.debug("同步包中无data字段")
                return

            # 解密数据
            message = None
            try:
                data = sync_data["data"]
                try:
                    data = base64.b64decode(data).decode("utf-8")
                    parsed_data = json.loads(data)
                    # 处理未加密的消息（如系统提示等）
                    msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                    if isinstance(parsed_data, dict) and 'chatType' in parsed_data:
                        if 'operation' in parsed_data and 'content' in parsed_data['operation']:
                            content = parsed_data['operation']['content']
                            if 'sessionArouse' in content:
                                # 处理系统引导消息
                                logger.info(f"[{msg_time}] 【{self.cookie_id}】【系统】小闲鱼智能提示:")
                                if 'arouseChatScriptInfo' in content['sessionArouse']:
                                    for qa in content['sessionArouse']['arouseChatScriptInfo']:
                                        logger.info(f"  - {qa['chatScrip']}")
                            elif 'contentType' in content:
                                # 其他类型的未加密消息
                                logger.debug(f"[{msg_time}] 【{self.cookie_id}】【系统】其他类型消息: {content}")
                        return
                    else:
                        # 如果不是系统消息，将解析的数据作为message
                        message = parsed_data
                except Exception as e:
                    # 如果JSON解析失败，尝试解密
                    decrypted_data = decrypt(data)
                    message = json.loads(decrypted_data)
            except Exception as e:
                logger.error(f"消息解密失败: {self._safe_str(e)}")
                return

            # 确保message不为空
            if message is None:
                logger.error("消息解析后为空")
                return

            # 确保message是字典类型
            if not isinstance(message, dict):
                logger.error(f"消息格式错误，期望字典但得到: {type(message)}")
                logger.debug(f"消息内容: {message}")
                return

            # 安全地获取用户ID
            user_id = None
            try:
                message_1 = message.get("1")
                if isinstance(message_1, str) and '@' in message_1:
                    user_id = message_1.split('@')[0]
                elif isinstance(message_1, dict):
                    # 如果message['1']是字典，尝试从嵌套结构中提取user_id
                    # 首先尝试 message["1"]["1"]["1"] 结构（与reply_server.py保持一致）
                    nested_user_id = message.get('1', {}).get('1', {}).get('1', '')
                    if nested_user_id and isinstance(nested_user_id, str):
                        user_id = nested_user_id.replace('@goofish', '')
                    # 如果上面没有提取到，尝试从 message["1"]["10"]["senderUserId"] 结构
                    elif "10" in message_1 and isinstance(message_1["10"], dict):
                        sender_user_id = message_1["10"].get("senderUserId")
                        if sender_user_id:
                            user_id = sender_user_id
                        else:
                            user_id = "unknown_user"
                    else:
                        user_id = "unknown_user"
                else:
                    user_id = "unknown_user"
            except Exception as e:
                logger.debug(f"提取用户ID失败: {self._safe_str(e)}")
                user_id = "unknown_user"



            # 安全地提取商品ID
            item_id = None
            try:
                if "1" in message and isinstance(message["1"], dict) and "10" in message["1"] and isinstance(message["1"]["10"], dict):
                    url_info = message["1"]["10"].get("reminderUrl", "")
                    if isinstance(url_info, str) and "itemId=" in url_info:
                        item_id = url_info.split("itemId=")[1].split("&")[0]

                # 如果没有提取到，使用辅助方法
                if not item_id:
                    item_id = self.extract_item_id_from_message(message)

                if not item_id:
                    item_id = f"auto_{user_id}_{int(time.time())}"
                    logger.debug(f"无法提取商品ID，使用默认值: {item_id}")

            except Exception as e:
                logger.error(f"提取商品ID时发生错误: {self._safe_str(e)}")
                item_id = f"auto_{user_id}_{int(time.time())}"
            # 处理订单状态消息
            try:
                logger.info(message)
                msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

                # 安全地检查订单状态
                red_reminder = None
                if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                    message_1 = message["1"]
                    if "10" in message_1 and isinstance(message_1["10"], dict):
                        red_reminder = message_1["10"].get("redReminder")
                        logger.info(f"[{msg_time}] 【订单管理】检测到red_reminder: {red_reminder}")
                    else:
                        logger.debug(f"[{msg_time}] 【订单管理】消息中没有找到message[1][10]字段")
                else:
                    logger.debug(f"[{msg_time}] 【订单管理】消息中没有找到message[1]字段")

                # 尝试解析订单消息（不管是什么状态）
                order_created = False
                logger.debug(f"[{msg_time}] 【订单管理】开始尝试解析订单消息")
                try:
                    from db_manager import db_manager
                    parsed_order = db_manager.parse_order_message(message)
                    if parsed_order:
                        logger.debug(f"[{msg_time}] 【订单管理】成功解析订单消息: {parsed_order}")
                        
                        # 获取发送者名称（提前获取，避免变量未定义错误）
                        message_10 = message_1.get("10", {}) if "1" in message and isinstance(message["1"], dict) else {}
                        temp_send_user_name = message_10.get("senderNick", message_10.get("reminderTitle", "未知用户"))
                        
                        # 构建订单数据
                        order_data = {
                            'order_id': parsed_order.get('order_id'),
                            'buyer_id': user_id,
                            'buyer_name': temp_send_user_name,  # 使用临时获取的买家名称
                            'item_id': item_id,  # 使用已提取的商品ID
                            'item_title': None,  # 可以从商品管理中查找
                            'order_status': parsed_order.get('order_status'),
                            'order_amount': None,  # 消息中通常不包含金额
                            'buyer_message': parsed_order.get('buyer_message'),
                            'seller_message': None,
                            'shipping_info': None,
                            'payment_time': msg_time if parsed_order.get('order_status') == '待发货' else None,
                            'shipping_time': msg_time if parsed_order.get('order_status') == '已发货' else None,
                            'delivery_time': None,
                            'refund_time': msg_time if parsed_order.get('order_status') == '已退款' else None,
                            'raw_message': parsed_order.get('raw_message')
                        }
                        
                        # 保存订单
                        success = db_manager.save_order(self.cookie_id, order_data)
                        if success:
                            logger.info(f"[{msg_time}] 【订单管理】成功创建/更新订单: {order_data.get('order_id')}, 买家: {user_id}, 状态: {order_data.get('order_status')}")
                            order_created = True
                            
                            # 异步获取订单详情（规格、数量、金额等信息）
                            order_id = order_data.get('order_id')
                            if order_id and not order_id.startswith('temp_'):  # 只对真实订单获取详情
                                try:
                                    logger.info(f"[{msg_time}] 【订单详情】开始获取订单 {order_id} 的详细信息")
                                    asyncio.create_task(self.fetch_order_detail_info(
                                        order_id=order_id,
                                        item_id=item_id,
                                        buyer_id=user_id,
                                        debug_headless=None  # 使用默认的无头模式
                                    ))
                                except Exception as detail_e:
                                    logger.error(f"[{msg_time}] 【订单详情】获取订单详情失败: {self._safe_str(detail_e)}")
                            
                            # 如果是临时订单，清理该买家的重复临时订单
                            if order_data.get('order_id', '').startswith('temp_'):
                                try:
                                    db_manager.cleanup_duplicate_temp_orders(self.cookie_id, user_id)
                                except Exception as e:
                                    logger.error(f"清理重复临时订单失败: {self._safe_str(e)}")
                            
                            # 如果订单状态为"待发货"且有商品ID，触发自动发货检查
                            if order_data.get('order_status') == '待发货' and item_id:
                                logger.info(f"[{msg_time}] 【订单管理】检测到待发货订单，准备检查自动发货规则")
                                # 异步执行自动发货检查，避免阻塞订单处理
                                asyncio.create_task(self._check_and_trigger_auto_delivery(
                                    websocket, order_data.get('order_id'), item_id, user_id, msg_time
                                ))
                        else:
                            logger.error(f"[{msg_time}] 【订单管理】保存订单失败: {order_data.get('order_id')}")
                    else:
                        logger.debug(f"[{msg_time}] 【订单管理】消息中未检测到订单信息")
                except Exception as e:
                    logger.error(f"[{msg_time}] 【订单管理】处理订单消息失败: {self._safe_str(e)}")

                if red_reminder == '等待买家付款':
                    # 从消息中提取用户ID
                    user_id = None
                    if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                        message_1 = message["1"]
                        if "10" in message_1 and isinstance(message_1["10"], dict):
                            user_id = message_1["10"].get("senderUserId")
                    
                    if not user_id:
                        logger.warning(f'[{msg_time}] 【系统】无法获取用户ID，跳过处理')
                        return
                    
                    user_url = f'https://www.goofish.com/personal?userId={user_id}'
                    logger.info(f'[{msg_time}] 【系统】等待买家 {user_url} 付款')
                    
                    # 添加30秒定时检查任务，检查订单是否已付款
                    try:
                        from db_manager import db_manager
                        # 从消息中提取订单ID和商品ID
                        order_id = None
                        item_id = None
                        
                        # 尝试从订单数据中获取订单ID和商品ID
                        if 'order_data' in locals() and order_data:
                            order_id = order_data.get('order_id')
                            item_id = order_data.get('item_id')
                        
                        # 如果没有从订单数据中获取到，尝试从消息中直接提取
                        if not order_id or not item_id:
                            try:
                                # 从消息中提取订单ID
                                if not order_id:
                                    # 方法1: 从extJson的updateKey中提取
                                    if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                        message_1 = message["1"]
                                        if "10" in message_1 and isinstance(message_1["10"], dict):
                                            ext_json_str = message_1["10"].get("extJson", "{}")
                                            try:
                                                ext_json = json.loads(ext_json_str)
                                                update_key = ext_json.get("updateKey", "")
                                                if ":" in update_key:
                                                    parts = update_key.split(":")
                                                    if len(parts) >= 2:
                                                        order_id = parts[1]
                                                        logger.debug(f"从updateKey提取订单ID: {order_id}")
                                            except Exception as e:
                                                logger.debug(f"从updateKey提取订单ID失败: {e}")
                                
                                # 方法2: 从targetUrl中提取订单ID
                                if not order_id:
                                    try:
                                        if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                            message_1 = message["1"]
                                            if "6" in message_1 and isinstance(message_1["6"], dict):
                                                if "3" in message_1["6"] and isinstance(message_1["6"]["3"], dict):
                                                    content_str = message_1["6"]["3"].get("5", "{}")
                                                    content_json = json.loads(content_str)
                                                    target_url = content_json.get("dxCard", {}).get("item", {}).get("main", {}).get("targetUrl", "")
                                                    if "id=" in target_url:
                                                        order_id = target_url.split("id=")[1].split("&")[0]
                                                        logger.debug(f"从targetUrl提取订单ID: {order_id}")
                                    except Exception as e:
                                        logger.debug(f"从targetUrl提取订单ID失败: {e}")
                                
                                # 方法3: 从按钮URL中提取订单ID
                                if not order_id:
                                    try:
                                        if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                            message_1 = message["1"]
                                            if "6" in message_1 and isinstance(message_1["6"], dict):
                                                if "3" in message_1["6"] and isinstance(message_1["6"]["3"], dict):
                                                    content_str = message_1["6"]["3"].get("5", "{}")
                                                    content_json = json.loads(content_str)
                                                    button_url = content_json.get("dxCard", {}).get("item", {}).get("main", {}).get("exContent", {}).get("button", {}).get("targetUrl", "")
                                                    if "bizOrderId=" in button_url:
                                                        order_id = button_url.split("bizOrderId=")[1].split("&")[0]
                                                        logger.debug(f"从按钮URL提取订单ID: {order_id}")
                                    except Exception as e:
                                        logger.debug(f"从按钮URL提取订单ID失败: {e}")
                                
                                # 从reminderUrl中提取商品ID
                                if not item_id:
                                    try:
                                        if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                            message_1 = message["1"]
                                            if "10" in message_1 and isinstance(message_1["10"], dict):
                                                reminder_url = message_1["10"].get("reminderUrl", "")
                                                if "itemId=" in reminder_url:
                                                    item_id = reminder_url.split("itemId=")[1].split("&")[0]
                                                    logger.debug(f"从reminderUrl提取商品ID: {item_id}")
                                    except Exception as e:
                                        logger.debug(f"从reminderUrl提取商品ID失败: {e}")
                                
                            except Exception as e:
                                logger.warning(f"从消息中提取订单信息失败: {self._safe_str(e)}")
                        
                        # 如果还是没有获取到，尝试使用数据库解析方法
                        if not order_id or not item_id:
                            try:
                                # 解析消息获取订单信息
                                parsed_order = db_manager.parse_order_message(message)
                                if parsed_order:
                                    if not order_id:
                                        order_id = parsed_order.get('order_id')
                                    if not item_id:
                                        item_id = parsed_order.get('item_id')
                            except Exception as e:
                                logger.warning(f"数据库解析订单消息失败: {self._safe_str(e)}")
                        
                        logger.info(f'[{msg_time}] 【系统】提取结果 - 订单ID: {order_id}, 商品ID: {item_id}, 用户ID: {user_id}')
                        
                        if order_id and item_id:
                            # 添加30秒后的定时检查任务
                            task_id = db_manager.add_pending_payment_check(
                                self.cookie_id, order_id, user_id, item_id, 30
                            )
                            if task_id > 0:
                                logger.info(f'[{msg_time}] 【系统】已添加订单 {order_id} 的30秒付款检查任务: {task_id}')
                            else:
                                logger.warning(f'[{msg_time}] 【系统】添加订单 {order_id} 付款检查任务失败')
                        else:
                            logger.warning(f'[{msg_time}] 【系统】无法获取订单ID或商品ID，跳过添加付款检查任务')
                            logger.warning(f'[{msg_time}] 【系统】缺失信息 - 订单ID: {order_id}, 商品ID: {item_id}')
                            
                    except Exception as e:
                        logger.error(f"[{msg_time}] 【系统】添加付款检查任务失败: {self._safe_str(e)}")
                        import traceback
                        logger.error(f"[{msg_time}] 【系统】详细错误信息: {traceback.format_exc()}")
                    
                    return
                elif red_reminder == '交易关闭':
                    # 从消息中提取用户ID
                    user_id = None
                    if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                        message_1 = message["1"]
                        if "10" in message_1 and isinstance(message_1["10"], dict):
                            user_id = message_1["10"].get("senderUserId")
                    
                    if user_id:
                        user_url = f'https://www.goofish.com/personal?userId={user_id}'
                        logger.info(f'[{msg_time}] 【系统】买家 {user_url} 交易关闭')
                    else:
                        logger.info(f'[{msg_time}] 【系统】买家交易关闭（无法获取用户ID）')
                    return
                elif red_reminder == '等待卖家发货':
                    # 从消息中提取用户ID
                    user_id = None
                    if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                        message_1 = message["1"]
                        if "10" in message_1 and isinstance(message_1["10"], dict):
                            user_id = message_1["10"].get("senderUserId")
                    
                    if user_id:
                        user_url = f'https://www.goofish.com/personal?userId={user_id}'
                        logger.info(f'[{msg_time}] 【系统】交易成功 {user_url} 等待卖家发货')
                    else:
                        logger.info(f'[{msg_time}] 【系统】交易成功，等待卖家发货（无法获取用户ID）')
                    
                    # 用户已下单，取消该对话的所有延迟引导任务
                    if user_id:
                        try:
                            from db_manager import db_manager
                            # 这里需要chat_id，但在订单状态消息中可能没有，可以尝试用user_id作为chat_id
                            # 或者取消该用户在该账号下的所有延迟引导任务
                            db_manager.cancel_delayed_guide_tasks(self.cookie_id, user_id, user_id)  
                        except Exception as e:
                            logger.error(f"用户下单后取消延迟引导任务失败: {self._safe_str(e)}")
                    
                    # return
            except Exception as e:
                logger.error(f"[{msg_time}] 【订单管理】处理订单状态消息异常: {self._safe_str(e)}")
                import traceback
                logger.error(f"[{msg_time}] 【订单管理】详细错误信息: {traceback.format_exc()}")

            # 判断是否为聊天消息
            if not self.is_chat_message(message):
                logger.debug("非聊天消息")
                return

            # 处理聊天消息
            try:
                # 安全地提取聊天消息信息
                if not (isinstance(message, dict) and "1" in message and isinstance(message["1"], dict)):
                    logger.error("消息格式错误：缺少必要的字段结构")
                    return

                message_1 = message["1"]
                if not isinstance(message_1.get("10"), dict):
                    logger.error("消息格式错误：缺少消息详情字段")
                    return

                create_time = int(message_1.get("5", 0))
                message_10 = message_1["10"]
                send_user_name = message_10.get("senderNick", message_10.get("reminderTitle", "未知用户"))
                send_user_id = message_10.get("senderUserId", "unknown")
                send_message = message_10.get("reminderContent", "")

                chat_id_raw = message_1.get("2", "")
                chat_id = chat_id_raw.split('@')[0] if '@' in str(chat_id_raw) else str(chat_id_raw)

            except Exception as e:
                logger.error(f"提取聊天消息信息失败: {self._safe_str(e)}")
                return

            # 格式化消息时间
            msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(create_time/1000))



            # 判断消息方向
            if send_user_id == self.myid:
                logger.info(f"[{msg_time}] 【手动发出】 商品({item_id}): {send_message}")

                # 检查是否为拉黑指令（手动发出的拉黑指令）
                if send_message.strip() == "拉黑":
                    # 对于手动发出的拉黑指令，我们需要拉黑对话的另一方
                    # 从chat_id中提取对方的用户信息
                    await self._handle_manual_blacklist_request(websocket, chat_id, msg_time)
                    return

                # 暂停该chat_id的自动回复10分钟
                pause_manager.pause_chat(chat_id, self.cookie_id)

                return
            else:
                logger.info(f"[{msg_time}] 【收到】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): {send_message}")

                # 用户发送了新消息，取消该对话的所有延迟引导任务
                try:
                    from db_manager import db_manager
                    db_manager.cancel_delayed_guide_tasks(self.cookie_id, send_user_id, chat_id)
                except Exception as e:
                    logger.error(f"取消延迟引导任务失败: {self._safe_str(e)}")

            # 首先检测是否为系统消息（最高优先级）
            if self._is_system_message(send_message, message):
                logger.info(f"[{msg_time}] 【{self.cookie_id}】系统消息，跳过自动回复: {send_message}")
                
                # 用户已付款，取消对应订单的待付款检查任务
                if user_id and self._is_auto_delivery_trigger(send_message):
                    try:
                        from db_manager import db_manager
                        # 从消息中提取订单ID
                        order_id = None
                        
                        # 尝试从订单数据中获取订单ID
                        if 'order_data' in locals() and order_data:
                            order_id = order_data.get('order_id')
                        
                        # 如果没有从订单数据中获取到，尝试从消息中直接提取
                        if not order_id:
                            try:
                                # 方法1: 从extJson的updateKey中提取
                                if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                    message_1 = message["1"]
                                    if "10" in message_1 and isinstance(message_1["10"], dict):
                                        ext_json_str = message_1["10"].get("extJson", "{}")
                                        try:
                                            ext_json = json.loads(ext_json_str)
                                            update_key = ext_json.get("updateKey", "")
                                            if ":" in update_key:
                                                parts = update_key.split(":")
                                                if len(parts) >= 2:
                                                    order_id = parts[1]
                                                    logger.debug(f"从updateKey提取订单ID: {order_id}")
                                        except Exception as e:
                                            logger.debug(f"从updateKey提取订单ID失败: {e}")
                                
                                
                                # 方法2: 从targetUrl中提取订单ID（支持多种消息格式）
                                if not order_id:
                                    try:
                                        if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                            message_1 = message["1"]
                                            if "6" in message_1 and isinstance(message_1["6"], dict):
                                                if "3" in message_1["6"] and isinstance(message_1["6"]["3"], dict):
                                                    content_str = message_1["6"]["3"].get("5", "{}")
                                                    content_json = json.loads(content_str)
                                                    
                                                    # 尝试从dxCard中提取
                                                    target_url = content_json.get("dxCard", {}).get("item", {}).get("main", {}).get("targetUrl", "")
                                                    if "id=" in target_url:
                                                        order_id = target_url.split("id=")[1].split("&")[0]
                                                        logger.debug(f"从dxCard targetUrl提取订单ID: {order_id}")
                                                    
                                                    # 尝试从dynamicOperation中提取
                                                    if not order_id:
                                                        dynamic_op = content_json.get("dynamicOperation", {})
                                                        if dynamic_op:
                                                            change_content = dynamic_op.get("changeContent", {})
                                                            dx_card = change_content.get("dxCard", {})
                                                            if dx_card:
                                                                target_url = dx_card.get("item", {}).get("main", {}).get("targetUrl", "")
                                                                if "id=" in target_url:
                                                                    order_id = target_url.split("id=")[1].split("&")[0]
                                                                    logger.debug(f"从dynamicOperation targetUrl提取订单ID: {order_id}")
                                    except Exception as e:
                                        logger.debug(f"从targetUrl提取订单ID失败: {e}")
                                
                                # 方法3: 从按钮URL中提取订单ID
                                if not order_id:
                                    try:
                                        if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                                            message_1 = message["1"]
                                            if "6" in message_1 and isinstance(message_1["6"], dict):
                                                if "3" in message_1["6"] and isinstance(message_1["6"]["3"], dict):
                                                    content_str = message_1["6"]["3"].get("5", "{}")
                                                    content_json = json.loads(content_str)
                                                    
                                                    # 尝试从dxCard按钮中提取
                                                    button_url = content_json.get("dxCard", {}).get("item", {}).get("main", {}).get("exContent", {}).get("button", {}).get("targetUrl", "")
                                                    if "orderId=" in button_url:
                                                        order_id = button_url.split("orderId=")[1].split("&")[0]
                                                        logger.debug(f"从dxCard按钮URL提取订单ID: {order_id}")
                                                    elif "id=" in button_url:
                                                        order_id = button_url.split("id=")[1].split("&")[0]
                                                        logger.debug(f"从dxCard按钮URL提取订单ID: {order_id}")
                                                    
                                                    # 尝试从dynamicOperation按钮中提取
                                                    if not order_id:
                                                        dynamic_op = content_json.get("dynamicOperation", {})
                                                        if dynamic_op:
                                                            change_content = dynamic_op.get("changeContent", {})
                                                            dx_card = change_content.get("dxCard", {})
                                                            if dx_card:
                                                                button_url = dx_card.get("item", {}).get("main", {}).get("exContent", {}).get("button", {}).get("targetUrl", "")
                                                                if "orderId=" in button_url:
                                                                    order_id = button_url.split("orderId=")[1].split("&")[0]
                                                                    logger.debug(f"从dynamicOperation按钮URL提取订单ID: {order_id}")
                                                                elif "id=" in button_url:
                                                                    order_id = button_url.split("id=")[1].split("&")[0]
                                                                    logger.debug(f"从dynamicOperation按钮URL提取订单ID: {order_id}")
                                    except Exception as e:
                                        logger.debug(f"从按钮URL提取订单ID失败: {e}")
                                
                            except Exception as e:
                                logger.warning(f"从消息中提取订单信息失败: {self._safe_str(e)}")
                        
                        # 如果还是没有获取到，尝试使用数据库解析方法
                        if not order_id:
                            try:
                                # 解析消息获取订单信息
                                parsed_order = db_manager.parse_order_message(message)
                                if parsed_order:
                                    order_id = parsed_order.get('order_id')
                            except Exception as e:
                                logger.warning(f"数据库解析订单消息失败: {self._safe_str(e)}")
                        
                        logger.info(f'[{msg_time}] 【系统】提取结果 - 订单ID: {order_id}, 用户ID: {user_id}')
                        
                        if order_id:
                            # 取消对应订单的待付款检查任务
                            cancelled = db_manager.cancel_pending_payment_check(self.cookie_id, order_id)
                            if cancelled:
                                logger.info(f'[{msg_time}] 【系统】已取消订单 {order_id} 的付款检查任务（用户已付款）')
                            else:
                                logger.debug(f'[{msg_time}] 【系统】订单 {order_id} 没有待取消的付款检查任务')
                        else:
                            logger.warning(f'[{msg_time}] 【系统】无法获取订单ID，跳过取消付款检查任务')
                            
                    except Exception as e:
                        logger.error(f"[{msg_time}] 【系统】取消付款检查任务失败: {self._safe_str(e)}")
                        import traceback
                        logger.error(f"[{msg_time}] 【系统】详细错误信息: {traceback.format_exc()}")
                
                # 检查是否为自动发货触发的系统消息
                if self._is_auto_delivery_trigger(send_message):
                    logger.info(f"[{msg_time}] 【{self.cookie_id}】检测到自动发货触发的系统消息，执行自动发货")
                    # 设置当前触发消息，供can_auto_delivery方法使用
                    self._current_trigger_message = send_message
                    try:
                        # 使用统一的自动发货处理方法
                        await self._handle_auto_delivery(websocket, message, send_user_name, send_user_id,
                                                       item_id, chat_id, msg_time)
                    finally:
                        # 清除触发消息标记
                        if hasattr(self, '_current_trigger_message'):
                            delattr(self, '_current_trigger_message')
                
                return

            # 检测人工客服转接请求（优先级第二）
            if self._is_manual_service_request(send_message):
                await self._handle_manual_service_request(websocket, chat_id, send_user_id,
                                                        send_user_name, send_message, msg_time)
                return

            # 检查是否为拉黑指令
            if send_message.strip() == "拉黑":
                await self._handle_blacklist_request(websocket, chat_id, send_user_id, send_user_name, msg_time)
                return

            # 自动回复消息
            if not AUTO_REPLY.get('enabled', True):
                logger.info(f"[{msg_time}] 【{self.cookie_id}】【系统】自动回复已禁用")
                return

            # 检查该chat_id是否处于暂停状态
            if pause_manager.is_chat_paused(chat_id):
                pause_status = pause_manager.get_pause_status(chat_id)
                if pause_status['type'] == 'permanent':
                    logger.info(f"[{msg_time}] 【{self.cookie_id}】【系统】chat_id {chat_id} 自动回复已永久暂停，原因: {pause_status['reason']}")
                else:
                    remaining_time = pause_status['remaining_time']
                    remaining_minutes = remaining_time // 60
                    remaining_seconds = remaining_time % 60
                    logger.info(f"[{msg_time}] 【{self.cookie_id}】【系统】chat_id {chat_id} 自动回复已暂停，剩余时间: {remaining_minutes}分{remaining_seconds}秒")
                return

            # 检查商品是否已配置关键词（只有配置了关键词的商品才能进行自动回复）
            try:
                from db_manager import db_manager
                if not db_manager.has_item_keywords(self.cookie_id, item_id):
                    logger.info(f"[{msg_time}] 【{self.cookie_id}】【系统】商品 {item_id} 未配置关键词，跳过自动回复")
                    return
            except Exception as e:
                logger.error(f"[{msg_time}] 【{self.cookie_id}】检查商品关键词配置失败: {e}")
                # 出错时保守处理，跳过回复
                return

            # 检查是否为图片消息（在商品已配置自动回复的情况下，图片消息回复默认提示）
            if self._is_image_message(message):
                logger.info(f'[{msg_time}] 【{self.cookie_id}】收到图片消息，自动回复提示')
                # 回复图片无法识别的提示
                await self.send_msg(websocket, chat_id, send_user_id, "亲，请发送文字消息，图片无法识别")
                logger.info(f"[{msg_time}] 【图片提示发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): 亲，请发送文字消息，图片无法识别")
                return

            # 构造用户URL
            user_url = f'https://www.goofish.com/personal?userId={send_user_id}'
                
            reply = None
            # 判断是否启用API回复
            if AUTO_REPLY.get('api', {}).get('enabled', False):
                reply = await self.get_api_reply(
                    msg_time, user_url, send_user_id, send_user_name,
                    item_id, send_message, chat_id
                )
                if reply:
                    # API回复成功，重置该对话的未匹配回复计数
                    from db_manager import db_manager
                    db_manager.reset_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)
                else:
                    logger.error(f"[{msg_time}] 【API调用失败】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): {send_message}")
            
            # 检查是否为自动发货触发消息
            if self._is_auto_delivery_trigger(send_message):
                # 设置当前触发消息，供can_auto_delivery方法使用
                self._current_trigger_message = send_message
                try:
                    # 使用统一的自动发货处理方法
                    await self._handle_auto_delivery(websocket, message, send_user_name, send_user_id,
                                                   item_id, chat_id, msg_time)
                finally:
                    # 清除触发消息标记
                    if hasattr(self, '_current_trigger_message'):
                        delattr(self, '_current_trigger_message')
                return

            elif send_message == '[卡片消息]':
                # 检查是否为"我已小刀，待刀成"的卡片消息
                try:
                    # 从消息中提取卡片内容
                    card_title = None
                    if isinstance(message, dict) and "1" in message and isinstance(message["1"], dict):
                        message_1 = message["1"]
                        if "6" in message_1 and isinstance(message_1["6"], dict):
                            message_6 = message_1["6"]
                            if "3" in message_6 and isinstance(message_6["3"], dict):
                                message_6_3 = message_6["3"]
                                if "5" in message_6_3:
                                    # 解析JSON内容
                                    try:
                                        card_content = json.loads(message_6_3["5"])
                                        if "dxCard" in card_content and "item" in card_content["dxCard"]:
                                            card_item = card_content["dxCard"]["item"]
                                            if "main" in card_item and "exContent" in card_item["main"]:
                                                ex_content = card_item["main"]["exContent"]
                                                card_title = ex_content.get("title", "")
                                    except (json.JSONDecodeError, KeyError) as e:
                                        logger.debug(f"解析卡片消息失败: {e}")

                    # 检查是否为"我已小刀，待刀成"
                    if card_title == "我已小刀，待刀成":
                        logger.info(f'[{msg_time}] 【{self.cookie_id}】【系统】检测到"我已小刀，待刀成"，准备自动免拼发货')
                        # 提取订单ID
                        order_id = self._extract_order_id(message)
                        if order_id:
                            # 延迟2秒后执行免拼发货
                            logger.info(f'[{msg_time}] 【{self.cookie_id}】延迟2秒后执行免拼发货...')
                            await asyncio.sleep(2)
                            # 调用自动免拼发货方法
                            result = await self.auto_freeshipping(order_id, item_id, send_user_id)
                            if result.get('success'):
                                logger.info(f'[{msg_time}] 【{self.cookie_id}】✅ 自动免拼发货成功')
                            else:
                                logger.warning(f'[{msg_time}] 【{self.cookie_id}】❌ 自动免拼发货失败: {result.get("error", "未知错误")}')
                            await self._handle_auto_delivery(websocket, message, send_user_name, send_user_id,
                                               item_id, chat_id, msg_time)
                            return
                        else:
                            logger.warning(f'[{msg_time}] 【{self.cookie_id}】❌ 未能提取到订单ID，无法执行免拼发货')
                        return
                    else:
                        logger.info(f'[{msg_time}] 【{self.cookie_id}】收到卡片消息，标题: {card_title or "未知"}')

                except Exception as e:
                    logger.error(f"处理卡片消息异常: {self._safe_str(e)}")

                # 如果不是目标卡片消息，继续正常处理流程
            # 记录回复来源
            reply_source = 'API'  # 默认假设是API回复

            # 如果API回复失败或未启用API，按新的优先级顺序处理
            if not reply:
                # 1. 首先检查用户余额是否足够进行关键词匹配（需要1聚合豆）
                from db_manager import db_manager
                user_id = db_manager.get_user_id_by_cookie(self.cookie_id)
                
                if user_id:
                    current_balance = db_manager.get_user_balance(user_id)
                    if current_balance < 3.0:
                        logger.warning(f"[{msg_time}] 【{self.cookie_id}】用户余额不足(当前:{current_balance}聚合豆，需要:3聚合豆)，跳过所有自动回复操作")
                        # 余额不足时不进行任何回复操作，直接返回
                        return
                    else:
                        # 余额充足，尝试关键词匹配
                        reply, match_type = await self.get_keyword_reply_with_type(send_user_name, send_user_id, send_message, item_id)
                        if reply:
                            # 只有商品ID关键词匹配成功才扣除聚合豆
                            if match_type == 'item_specific':
                                balance_sufficient = db_manager.check_and_consume_balance(
                                    user_id=user_id,
                                    amount=3.0,
                                    description=f"关键词匹配回复 - 商品ID:{item_id}, 关键词匹配类型:{match_type}",
                                    order_id=None
                                )
                                
                                if not balance_sufficient:
                                    logger.warning(f"[{msg_time}] 【{self.cookie_id}】用户余额不足，跳过关键词自动回复")
                                    reply = None  # 重置reply，继续后续逻辑
                                else:
                                    reply_source = '关键词'  # 标记为关键词回复
                                    # 关键词匹配成功，重置该对话的未匹配回复计数
                                    db_manager.reset_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)
                                    
                                    # 商品ID关键词匹配成功才触发延迟引导话术任务
                                    await self._add_delayed_guide_task(send_user_id, chat_id, item_id)
                                    logger.info(f"商品ID关键词匹配，已添加延迟引导任务")
                            else:
                                # 通用关键词匹配不扣除聚合豆
                                reply_source = '关键词'  # 标记为关键词回复
                                # 关键词匹配成功，重置该对话的未匹配回复计数
                                db_manager.reset_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)
                                logger.info(f"通用关键词匹配（{match_type}），不扣除聚合豆，不触发延迟引导任务")
                else:
                    logger.error(f"[{msg_time}] 【{self.cookie_id}】无法获取用户ID，跳过关键词匹配")
                
                # 2. 如果关键词匹配失败或余额不足，检查商品专属回复
                if not reply:
                    # 检查商品专属回复（如果尚未发送过）
                    if not db_manager.has_chat_first_replied(self.cookie_id, chat_id):
                        exclusive_reply = db_manager.get_item_exclusive_reply(self.cookie_id, item_id)
                        if exclusive_reply and exclusive_reply.get('enabled', False):
                            # 使用商品专属回复语
                            reply = exclusive_reply.get('reply_content', '')
                            # 处理变量替换
                            reply = reply.replace('{send_user_name}', send_user_name)
                            reply = reply.replace('{send_user_id}', send_user_id)
                            reply = reply.replace('{send_message}', send_message)
                            reply_source = '专属回复'
                            # 标记对话已经回复过专属回复
                            db_manager.mark_chat_has_replied(self.cookie_id, chat_id)
                            # 重置该对话的未匹配回复计数
                            db_manager.reset_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)
                            logger.info(f"【{self.cookie_id}】对话 {chat_id} 使用商品专属回复语")
                
                # 3. 如果专属回复也没有或已发送过，尝试AI回复
                if not reply:
                    # 关键词匹配失败且无专属回复，如果AI开关打开，尝试AI回复
                    reply = await self.get_ai_reply(send_user_name, send_user_id, send_message, item_id, chat_id)
                    if reply:
                        reply_source = 'AI'  # 标记为AI回复
                        # AI回复成功，重置该对话的未匹配回复计数
                        from db_manager import db_manager
                        db_manager.reset_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)
                    else:
                        # 4. 最后使用默认回复
                        reply = await self.get_default_reply(send_user_name, send_user_id, send_message, chat_id)
                        if reply:
                            reply_source = '默认'  # 标记为默认回复
                            # 默认回复成功，重置该对话的未匹配回复计数
                            from db_manager import db_manager
                            db_manager.reset_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)

            # 注意：这里只有商品ID，没有标题和详情，根据新的规则不保存到数据库
            # 商品信息会在其他有完整信息的地方保存（如发货规则匹配时）

            # 如果没有任何回复，根据首次回复逻辑处理
            if not reply:
                from db_manager import db_manager

                # 检查是否为对话的首次回复
                is_first_reply = db_manager.is_chat_first_reply(self.cookie_id, chat_id)

                if is_first_reply:
                    # 首次回复：使用账号管理设置的默认回复内容
                    reply = await self.get_default_reply(send_user_name, send_user_id, send_message, chat_id)
                    if reply:
                        reply_source = '首次默认'  # 标记为首次默认回复
                        # 标记对话已经回复过
                        db_manager.mark_chat_first_reply(self.cookie_id, chat_id)
                        logger.info(f"【{self.cookie_id}】对话 {chat_id} 首次回复，使用账号默认回复")
                    else:
                        # 如果账号没有设置默认回复，使用系统未匹配回复
                        unmatch_reply = db_manager.get_system_setting('unmatch_default_reply')
                        reply = unmatch_reply if unmatch_reply else "抱歉，根据您发送的内容，未能识别到可用门店"
                        reply_source = '首次系统'
                        # 标记对话已经回复过
                        db_manager.mark_chat_first_reply(self.cookie_id, chat_id)
                        logger.info(f"【{self.cookie_id}】对话 {chat_id} 首次回复，使用系统未匹配回复")
                else:
                    # 非首次回复：检查未匹配回复次数限制
                    # 从系统配置中获取最大未匹配回复次数限制，默认为3次
                    max_unmatch_count = int(db_manager.get_system_setting('max_unmatch_reply_count') or 3)
                    if not db_manager.check_unmatch_reply_limit(self.cookie_id, send_user_id, chat_id, max_count=max_unmatch_count):
                        # 检查是否已发送过最终提醒消息
                        if not db_manager.has_sent_final_reminder(self.cookie_id, send_user_id, chat_id):
                            # 发送最终提醒消息
                            final_reminder = "多次未匹配成功则表示您发送的目标门店不可用（或者您可以发送\"转人工\"，人工客服将为您手动查询）"
                            try:
                                await self.send_msg(websocket, chat_id, send_user_id, final_reminder)
                                # 标记已发送最终提醒消息
                                db_manager.mark_final_reminder_sent(self.cookie_id, send_user_id, chat_id)
                                logger.info(f"【{self.cookie_id}】用户 {send_user_id} 在对话 {chat_id} 中未匹配回复次数已达上限({max_unmatch_count}次)，已发送最终提醒消息")
                            except Exception as e:
                                logger.error(f"发送最终提醒消息失败: {self._safe_str(e)}")
                        else:
                            logger.info(f"【{self.cookie_id}】用户 {send_user_id} 在对话 {chat_id} 中未匹配回复次数已达上限({max_unmatch_count}次)，已发送过最终提醒消息，跳过发送")
                        return  # 直接返回，不发送任何回复
                    
                    # 使用系统设置中的未匹配回复
                    unmatch_reply = db_manager.get_system_setting('unmatch_default_reply')
                    reply = unmatch_reply if unmatch_reply else "抱歉，根据您发送的内容，未能识别到可用门店"
                    reply_source = '系统'
                    
                    # 记录未匹配回复次数
                    db_manager.increment_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)
                    logger.info(f"【{self.cookie_id}】对话 {chat_id} 非首次回复，使用系统未匹配回复，当前次数：{db_manager.get_unmatch_reply_count(self.cookie_id, send_user_id, chat_id)}")
                
                # 只有关键字未匹配成功时才发送通知
                # await self.send_notification(send_user_name, send_user_id, send_message, item_id)  # 已关闭未成功匹配消息内容通知

            # 发送回复消息
            # 检查是否是特殊格式的消息
            if reply.startswith("__BATCH_DATA_IMAGE_WITH_NOTE__"):
                # 批量数据图片+备注分开发送
                parts = reply.replace("__BATCH_DATA_IMAGE_WITH_NOTE__", "").split("|")
                if len(parts) >= 4:
                    card_id_str, image_url, actual_data, card_description = parts[0], parts[1], parts[2], parts[3]
                    try:
                        # 先发送图片
                        await self.send_image_msg(websocket, chat_id, send_user_id, image_url)
                        msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                        logger.info(f"[{msg_time}] 【{reply_source}图片发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): 图片 {image_url}")
                        
                        # 再发送备注信息
                        if card_description and card_description.strip():
                            # 添加短暂延迟，确保图片和备注消息分开显示
                            await asyncio.sleep(1)
                            processed_description = card_description.replace('{DELIVERY_CONTENT}', actual_data)
                            await self.send_msg(websocket, chat_id, send_user_id, processed_description)
                            logger.info(f"[{msg_time}] 【{reply_source}备注发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): {processed_description}")
                    except Exception as e:
                        logger.error(f"批量数据图片+备注发送失败: {self._safe_str(e)}")
                        await self.send_msg(websocket, chat_id, send_user_id, "抱歉，发送失败，请稍后重试。")
                else:
                    logger.error(f"批量数据图片+备注格式错误: {reply}")
                    await self.send_msg(websocket, chat_id, send_user_id, "抱歉，发送失败，请稍后重试。")
            elif reply.startswith("__IMAGE_WITH_NOTE__"):
                # 图片+备注分开发送
                parts = reply.replace("__IMAGE_WITH_NOTE__", "").split("|", 2)
                if len(parts) >= 3:
                    card_id_str, image_url, card_description = parts[0], parts[1], parts[2]
                    try:
                        # 先发送图片
                        await self.send_image_msg(websocket, chat_id, send_user_id, image_url)
                        msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                        logger.info(f"[{msg_time}] 【{reply_source}图片发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): 图片 {image_url}")
                        
                        # 再发送备注信息
                        if card_description and card_description.strip():
                            # 添加短暂延迟，确保图片和备注消息分开显示
                            await asyncio.sleep(1)
                            processed_description = card_description.replace('{DELIVERY_CONTENT}', '图片卡券')
                            await self.send_msg(websocket, chat_id, send_user_id, processed_description)
                            logger.info(f"[{msg_time}] 【{reply_source}备注发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): {processed_description}")
                    except Exception as e:
                        logger.error(f"图片+备注发送失败: {self._safe_str(e)}")
                        await self.send_msg(websocket, chat_id, send_user_id, "抱歉，发送失败，请稍后重试。")
                else:
                    logger.error(f"图片+备注格式错误: {reply}")
                    await self.send_msg(websocket, chat_id, send_user_id, "抱歉，发送失败，请稍后重试。")
            elif reply.startswith("__IMAGE_SEND__"):
                # 传统图片发送标记（关键词回复不包含卡券ID）
                image_url = reply.replace("__IMAGE_SEND__", "")
                # 发送图片消息
                try:
                    await self.send_image_msg(websocket, chat_id, send_user_id, image_url)
                    # 记录发出的图片消息
                    msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                    logger.info(f"[{msg_time}] 【{reply_source}图片发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): 图片 {image_url}")
                except Exception as e:
                    # 图片发送失败，发送错误提示
                    logger.error(f"图片发送失败: {self._safe_str(e)}")
                    await self.send_msg(websocket, chat_id, send_user_id, "抱歉，图片发送失败，请稍后重试。")
                    msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                    logger.error(f"[{msg_time}] 【{reply_source}图片发送失败】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id})")
            elif reply.startswith("__BATCH_DATA_IMAGE__"):
                # 批量数据图片发送（不含备注）
                parts = reply.replace("__BATCH_DATA_IMAGE__", "").split("|")
                if len(parts) >= 3:
                    card_id_str, image_url, actual_data = parts[0], parts[1], parts[2]
                    try:
                        # 发送图片
                        await self.send_image_msg(websocket, chat_id, send_user_id, image_url)
                        msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                        logger.info(f"[{msg_time}] 【{reply_source}批量数据图片发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): 图片 {image_url}")
                    except Exception as e:
                        logger.error(f"批量数据图片发送失败: {self._safe_str(e)}")
                        await self.send_msg(websocket, chat_id, send_user_id, "抱歉，发送失败，请稍后重试。")
                else:
                    logger.error(f"批量数据图片格式错误: {reply}")
                    await self.send_msg(websocket, chat_id, send_user_id, "抱歉，发送失败，请稍后重试。")
            else:
                # 普通文本消息
                await self.send_msg(websocket, chat_id, send_user_id, reply)
                # 记录发出的消息
                msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                logger.info(f"[{msg_time}] 【{reply_source}发出】用户: {send_user_name} (ID: {send_user_id}), 商品({item_id}): {reply}")
            
        except Exception as e:
            logger.error(f"处理消息时发生错误: {self._safe_str(e)}")
            logger.debug(f"原始消息: {message_data}")

    async def main(self):
        """主程序入口"""
        try:
            logger.info(f"【{self.cookie_id}】开始启动XianyuLive主程序...")
            await self.create_session()  # 创建session
            logger.info(f"【{self.cookie_id}】Session创建完成，开始WebSocket连接循环...")

            while True:
                try:
                    # 检查账号是否启用
                    from cookie_manager import manager as cookie_manager
                    if cookie_manager and not cookie_manager.get_cookie_status(self.cookie_id):
                        logger.info(f"【{self.cookie_id}】账号已禁用，停止主循环")
                        break

                    # 检查Token状态，如果为失效状态则等待用户手动更新
                    from db_manager import db_manager
                    token_status = db_manager.get_token_status(self.cookie_id)
                    if token_status == 'invalid':
                        logger.warning(f"【{self.cookie_id}】Token状态为失效，自动刷新功能已完全禁用，请手动更新Cookie")
                        
                        # 发送Token失效通知
                        await self.send_token_refresh_notification(
                            f"账号 {self.cookie_id} Token已失效，自动刷新功能已禁用，请手动更新Cookie", 
                            "token_invalid"
                        )
                        
                        logger.info(f"【{self.cookie_id}】等待1小时后重新检查Token状态...")
                        await asyncio.sleep(3600)  # 等待1小时后重新检查
                        continue
                        
                        # 注释掉的自动刷新逻辑 - 已禁用
                        # logger.info(f"【{self.cookie_id}】Token状态为失效，尝试自动刷新...")
                        # 
                        # # 首先尝试刷新token
                        # logger.info(f"【{self.cookie_id}】步骤1: 尝试刷新Token...")
                        # refresh_success = await self.refresh_token(skip_restart=True)
                        # 
                        # if refresh_success:
                        #     logger.info(f"【{self.cookie_id}】Token刷新成功，继续连接")
                        #     # Token刷新成功，更新状态并继续循环
                        #     db_manager.update_token_status(self.cookie_id, 'valid')
                        #     continue
                        # else:
                        #     logger.warning(f"【{self.cookie_id}】Token刷新失败，自动续期功能已移除，需要手动更新Cookie")
                        #     logger.error(f"【{self.cookie_id}】Token失效且自动续期功能已移除，等待5分钟后重试...")
                        #     await asyncio.sleep(300)  # 等待5分钟后重试
                        #     continue

                    headers = WEBSOCKET_HEADERS.copy()
                    headers['Cookie'] = self.cookies_str

                    logger.info(f"【{self.cookie_id}】准备建立WebSocket连接到: {self.base_url}")
                    logger.debug(f"【{self.cookie_id}】WebSocket headers: {headers}")

                    # 兼容不同版本的websockets库
                    async with await self._create_websocket_connection(headers) as websocket:
                        logger.info(f"【{self.cookie_id}】WebSocket连接建立成功！")
                        self.ws = websocket

                        # 更新Token状态为有效（基于连接成功）
                        self._update_token_status_based_on_connection(True)

                        # 注册到延迟引导调度器
                        try:
                            from delayed_guide_scheduler import delayed_guide_scheduler
                            delayed_guide_scheduler.register_xianyu_instance(self.cookie_id, self)
                        except Exception as e:
                            logger.error(f"注册到延迟引导调度器失败: {self._safe_str(e)}")

                        # 注册到待付款检查调度器
                        try:
                            from pending_payment_scheduler import pending_payment_scheduler
                            pending_payment_scheduler.register_xianyu_instance(self.cookie_id, self)
                        except Exception as e:
                            logger.error(f"注册到待付款检查调度器失败: {self._safe_str(e)}")

                        logger.info(f"【{self.cookie_id}】开始初始化WebSocket连接...")
                        await self.init(websocket)
                        logger.info(f"【{self.cookie_id}】WebSocket初始化完成！")

                        # 启动心跳任务
                        logger.info(f"【{self.cookie_id}】启动心跳任务...")
                        self.heartbeat_task = asyncio.create_task(self.heartbeat_loop(websocket))

                        # Token刷新循环已完全移除
                        logger.info(f"【{self.cookie_id}】Token刷新循环已禁用，仅在cookie更新时刷新")

                        # 启动暂停记录清理任务
                        if not self.cleanup_task:
                            logger.info(f"【{self.cookie_id}】启动暂停记录清理任务...")
                            self.cleanup_task = asyncio.create_task(self.pause_cleanup_loop())

                        logger.info(f"【{self.cookie_id}】开始监听WebSocket消息...")

                        async for message in websocket:
                            try:
                                message_data = json.loads(message)

                                # 处理心跳响应
                                if await self.handle_heartbeat_response(message_data):
                                    continue

                                # 处理其他消息
                                await self.handle_message(message_data, websocket)

                            except Exception as e:
                                logger.error(f"处理消息出错: {self._safe_str(e)}")
                                continue

                except Exception as e:
                    logger.error(f"WebSocket连接异常: {self._safe_str(e)}")
                    
                    # 从延迟引导调度器中注销
                    try:
                        from delayed_guide_scheduler import delayed_guide_scheduler
                        delayed_guide_scheduler.unregister_xianyu_instance(self.cookie_id)
                    except Exception as reg_e:
                        logger.error(f"从延迟引导调度器注销失败: {self._safe_str(reg_e)}")
                    
                    # 从待付款检查调度器中注销
                    try:
                        from pending_payment_scheduler import pending_payment_scheduler
                        pending_payment_scheduler.unregister_xianyu_instance(self.cookie_id)
                    except Exception as reg_e:
                        logger.error(f"从待付款检查调度器注销失败: {self._safe_str(reg_e)}")
                    
                    if self.heartbeat_task:
                        self.heartbeat_task.cancel()
                    if self.cleanup_task:
                        self.cleanup_task.cancel()
                    await asyncio.sleep(5)  # 等待5秒后重试
                    continue
        finally:
            # 从延迟引导调度器中注销
            try:
                from delayed_guide_scheduler import delayed_guide_scheduler
                delayed_guide_scheduler.unregister_xianyu_instance(self.cookie_id)
            except Exception as e:
                logger.error(f"最终清理时从延迟引导调度器注销失败: {self._safe_str(e)}")
            
            # 从待付款检查调度器中注销
            try:
                from pending_payment_scheduler import pending_payment_scheduler
                pending_payment_scheduler.unregister_xianyu_instance(self.cookie_id)
            except Exception as e:
                logger.error(f"最终清理时从待付款检查调度器注销失败: {self._safe_str(e)}")
                
            # 清理所有任务
            if self.heartbeat_task:
                self.heartbeat_task.cancel()
            if self.cleanup_task:
                self.cleanup_task.cancel()
            await self.close_session()  # 确保关闭session

    async def get_item_list_info(self, page_number=1, page_size=20, retry_count=0):
        """获取商品信息，自动处理token失效的情况

        Args:
            page_number (int): 页码，从1开始
            page_size (int): 每页数量，默认20
            retry_count (int): 重试次数，内部使用
        """
        if retry_count >= 4:  # 最多重试3次
            logger.error("获取商品信息失败，重试次数过多")
            return {"error": "获取商品信息失败，重试次数过多"}

        # 检查Token状态，如果为失效状态则停止重连
        from db_manager import db_manager
        token_status = db_manager.get_token_status(self.cookie_id)
        if token_status == 'invalid':
            logger.info(f"【{self.cookie_id}】Token状态为失效，停止重连")
            return

        # Token刷新功能已禁用
        # 如果是重试（retry_count > 0），强制刷新token
        if retry_count > 0:
            logger.info(f"重试第{retry_count}次，但Token刷新功能已禁用，使用现有Token")
        else:
            # 使用现有的token，不再自动刷新
            logger.debug(f"使用现有Token，自动刷新功能已禁用")

        # 确保session已创建
        if not self.session:
            await self.create_session()

        params = {
            'jsv': '2.7.2',
            'appKey': '34839810',
            't': str(int(time.time()) * 1000),
            'sign': '',
            'v': '1.0',
            'type': 'originaljson',
            'accountSite': 'xianyu',
            'dataType': 'json',
            'timeout': '20000',
            'api': 'mtop.idle.web.xyh.item.list',
            'sessionOption': 'AutoLoginOnly',
            'spm_cnt': 'a21ybx.im.0.0',
            'spm_pre': 'a21ybx.collection.menu.1.272b5141NafCNK'
        }

        data = {
            'needGroupInfo': False,
            'pageNumber': page_number,
            'pageSize': page_size,
            'groupName': '在售',
            'groupId': '58877261',
            'defaultGroup': True,
            "userId": self.myid
        }

        # 始终从最新的cookies中获取_m_h5_tk token（刷新后cookies会被更新）
        token = trans_cookies(self.cookies_str).get('_m_h5_tk', '').split('_')[0] if trans_cookies(self.cookies_str).get('_m_h5_tk') else ''

        logger.warning(f"准备获取商品列表，token: {token}")
        if token:
            logger.debug(f"使用cookies中的_m_h5_tk token: {token}")
        else:
            logger.warning("cookies中没有找到_m_h5_tk token")

        # 生成签名
        data_val = json.dumps(data, separators=(',', ':'))
        sign = generate_sign(params['t'], token, data_val)
        params['sign'] = sign

        try:
            async with self.session.post(
                'https://h5api.m.goofish.com/h5/mtop.idle.web.xyh.item.list/1.0/',
                params=params,
                data={'data': data_val}
            ) as response:
                res_json = await response.json()

                # 注释掉的自动更新Cookie逻辑 - 已禁用
                # if 'set-cookie' in response.headers:
                #     new_cookies = {}
                #     for cookie in response.headers.getall('set-cookie', []):
                #         if '=' in cookie:
                #             name, value = cookie.split(';')[0].split('=', 1)
                #             new_cookies[name.strip()] = value.strip()
                #     
                #     # 更新cookies
                #     if new_cookies:
                #         self.cookies.update(new_cookies)
                #         # 生成新的cookie字符串
                #         self.cookies_str = '; '.join([f"{k}={v}" for k, v in self.cookies.items()])
                #         # 更新数据库中的Cookie
                #         await self.update_config_cookies()
                #         logger.debug("已更新Cookie到数据库")

                logger.info(f"商品信息获取响应: {res_json}")

                # 检查响应是否成功
                if res_json.get('ret') and res_json['ret'][0] == 'SUCCESS::调用成功':
                    items_data = res_json.get('data', {})
                    # 从cardList中提取商品信息
                    card_list = items_data.get('cardList', [])

                    # 解析cardList中的商品信息
                    items_list = []
                    for card in card_list:
                        card_data = card.get('cardData', {})
                        if card_data:
                            # 提取商品基本信息
                            item_info = {
                                'id': card_data.get('id', ''),
                                'title': card_data.get('title', ''),
                                'price': card_data.get('priceInfo', {}).get('price', ''),
                                'price_text': card_data.get('priceInfo', {}).get('preText', '') + card_data.get('priceInfo', {}).get('price', ''),
                                'category_id': card_data.get('categoryId', ''),
                                'auction_type': card_data.get('auctionType', ''),
                                'item_status': card_data.get('itemStatus', 0),
                                'detail_url': card_data.get('detailUrl', ''),
                                'pic_info': card_data.get('picInfo', {}),
                                'detail_params': card_data.get('detailParams', {}),
                                'track_params': card_data.get('trackParams', {}),
                                'item_label_data': card_data.get('itemLabelDataVO', {}),
                                'card_type': card.get('cardType', 0)
                            }
                            items_list.append(item_info)

                    logger.info(f"成功获取到 {len(items_list)} 个商品")

                    # 打印商品详细信息到控制台
                    print("\n" + "="*80)
                    print(f"📦 账号 {self.myid} 的商品列表 (第{page_number}页，{len(items_list)} 个商品)")
                    print("="*80)

                    for i, item in enumerate(items_list, 1):
                        print(f"\n🔸 商品 {i}:")
                        print(f"   商品ID: {item.get('id', 'N/A')}")
                        print(f"   商品标题: {item.get('title', 'N/A')}")
                        print(f"   价格: {item.get('price_text', 'N/A')}")
                        print(f"   分类ID: {item.get('category_id', 'N/A')}")
                        print(f"   商品状态: {item.get('item_status', 'N/A')}")
                        print(f"   拍卖类型: {item.get('auction_type', 'N/A')}")
                        print(f"   详情链接: {item.get('detail_url', 'N/A')}")
                        if item.get('pic_info'):
                            pic_info = item['pic_info']
                            print(f"   图片信息: {pic_info.get('width', 'N/A')}x{pic_info.get('height', 'N/A')}")
                            print(f"   图片链接: {pic_info.get('picUrl', 'N/A')}")
                        print(f"   完整信息: {json.dumps(item, ensure_ascii=False, indent=2)}")

                    print("\n" + "="*80)
                    print("✅ 商品列表获取完成")
                    print("="*80)

                    # 自动保存商品信息到数据库
                    if items_list:
                        saved_count = await self.save_items_list_to_db(items_list)
                        logger.info(f"已将 {saved_count} 个商品信息保存到数据库")

                    return {
                        "success": True,
                        "page_number": page_number,
                        "page_size": page_size,
                        "current_count": len(items_list),
                        "items": items_list,
                        "saved_count": saved_count if items_list else 0,
                        "raw_data": items_data  # 保留原始数据以备调试
                    }
                else:
                    # 检查是否是token失效
                    error_msg = res_json.get('ret', [''])[0] if res_json.get('ret') else ''
                    if 'FAIL_SYS_TOKEN_EXOIRED' in error_msg or 'token' in error_msg.lower():
                        logger.warning(f"Token失效，准备重试: {error_msg}")
                        
                        # 检测到Token失效时，记录日志
                        logger.warning(f"【{self.cookie_id}】商品列表API检测到Token失效，自动续期功能已移除，需要手动更新Cookie")
                        
                        await asyncio.sleep(0.5)
                        return await self.get_item_list_info(page_number, page_size, retry_count + 1)
                    else:
                        logger.error(f"获取商品信息失败: {res_json}")
                        return {"error": f"获取商品信息失败: {error_msg}"}

        except Exception as e:
            logger.error(f"商品信息API请求异常: {self._safe_str(e)}")
            await asyncio.sleep(0.5)
            return await self.get_item_list_info(page_number, page_size, retry_count + 1)

    async def get_all_items(self, page_size=20, max_pages=None):
        """获取所有商品信息（自动分页）

        Args:
            page_size (int): 每页数量，默认20
            max_pages (int): 最大页数限制，None表示无限制

        Returns:
            dict: 包含所有商品信息的字典
        """
        all_items = []
        page_number = 1
        total_saved = 0

        logger.info(f"开始获取所有商品信息，每页{page_size}条")

        while True:
            if max_pages and page_number > max_pages:
                logger.info(f"达到最大页数限制 {max_pages}，停止获取")
                break

            logger.info(f"正在获取第 {page_number} 页...")
            result = await self.get_item_list_info(page_number, page_size)

            if not result.get("success"):
                logger.error(f"获取第 {page_number} 页失败: {result}")
                break

            current_items = result.get("items", [])
            if not current_items:
                logger.info(f"第 {page_number} 页没有数据，获取完成")
                break

            all_items.extend(current_items)
            total_saved += result.get("saved_count", 0)

            logger.info(f"第 {page_number} 页获取到 {len(current_items)} 个商品")

            # 如果当前页商品数量少于页面大小，说明已经是最后一页
            if len(current_items) < page_size:
                logger.info(f"第 {page_number} 页商品数量({len(current_items)})少于页面大小({page_size})，获取完成")
                break

            page_number += 1

            # 添加延迟避免请求过快
            await asyncio.sleep(1)

        logger.info(f"所有商品获取完成，共 {len(all_items)} 个商品，保存了 {total_saved} 个")

        return {
            "success": True,
            "total_pages": page_number,
            "total_count": len(all_items),
            "total_saved": total_saved,
            "items": all_items
        }

    async def send_image_msg(self, ws, cid, toid, image_url, width=800, height=600, card_id=None):
        """发送图片消息"""
        try:
            # 检查图片URL是否需要上传到CDN
            original_url = image_url

            if self._is_cdn_url(image_url):
                # 已经是CDN链接，直接使用
                logger.info(f"【{self.cookie_id}】使用已有的CDN图片链接: {image_url}")
            elif image_url.startswith('/static/uploads/') or image_url.startswith('static/uploads/'):
                # 本地图片，需要上传到闲鱼CDN
                local_image_path = image_url.replace('/static/uploads/', 'static/uploads/').replace('static/uploads/', 'static/uploads/')
                # 标准化路径分隔符
                local_image_path = local_image_path.replace('/', os.sep)
                if os.path.exists(local_image_path):
                    logger.info(f"【{self.cookie_id}】准备上传本地图片到闲鱼CDN: {local_image_path}")

                    # 使用图片上传器上传到闲鱼CDN
                    from utils.image_uploader import ImageUploader
                    uploader = ImageUploader(self.cookies_str)

                    async with uploader:
                        cdn_url = await uploader.upload_image(local_image_path)
                        if cdn_url:
                            logger.info(f"【{self.cookie_id}】图片上传成功，CDN URL: {cdn_url}")
                            image_url = cdn_url

                            # 如果是卡券图片，更新数据库中的图片URL
                            if card_id is not None:
                                await self._update_card_image_url(card_id, cdn_url)

                            # 获取实际图片尺寸
                            from utils.image_utils import image_manager
                            try:
                                actual_width, actual_height = image_manager.get_image_size(local_image_path)
                                if actual_width and actual_height:
                                    width, height = actual_width, actual_height
                                    logger.info(f"【{self.cookie_id}】获取到实际图片尺寸: {width}x{height}")
                            except Exception as e:
                                logger.warning(f"【{self.cookie_id}】获取图片尺寸失败，使用默认尺寸: {e}")
                        else:
                            logger.error(f"【{self.cookie_id}】图片上传失败: {local_image_path}")
                            raise Exception(f"图片上传失败: {local_image_path}")
                else:
                    logger.error(f"【{self.cookie_id}】本地图片文件不存在: {local_image_path}")
                    raise Exception(f"本地图片文件不存在: {local_image_path}")
            else:
                logger.warning(f"【{self.cookie_id}】未知的图片URL格式: {image_url}")

            # 记录详细的图片信息
            logger.info(f"【{self.cookie_id}】准备发送图片消息:")
            logger.info(f"  - 原始URL: {original_url}")
            logger.info(f"  - CDN URL: {image_url}")
            logger.info(f"  - 图片尺寸: {width}x{height}")
            logger.info(f"  - 聊天ID: {cid}")
            logger.info(f"  - 接收者ID: {toid}")

            # 构造图片消息内容 - 使用正确的闲鱼格式
            image_content = {
                "contentType": 2,  # 图片消息类型
                "image": {
                    "pics": [
                        {
                            "height": int(height),
                            "type": 0,
                            "url": image_url,
                            "width": int(width)
                        }
                    ]
                }
            }

            # Base64编码
            content_json = json.dumps(image_content, ensure_ascii=False)
            content_base64 = str(base64.b64encode(content_json.encode('utf-8')), 'utf-8')

            logger.info(f"【{self.cookie_id}】图片内容JSON: {content_json}")
            logger.info(f"【{self.cookie_id}】Base64编码长度: {len(content_base64)}")

            # 构造WebSocket消息（完全参考send_msg的格式）
            msg = {
                "lwp": "/r/MessageSend/sendByReceiverScope",
                "headers": {
                    "mid": generate_mid()
                },
                "body": [
                    {
                        "uuid": generate_uuid(),
                        "cid": f"{cid}@goofish",
                        "conversationType": 1,
                        "content": {
                            "contentType": 101,
                            "custom": {
                                "type": 1,
                                "data": content_base64
                            }
                        },
                        "redPointPolicy": 0,
                        "extension": {
                            "extJson": "{}"
                        },
                        "ctx": {
                            "appVersion": "1.0",
                            "platform": "web"
                        },
                        "mtags": {},
                        "msgReadStatusSetting": 1
                    },
                    {
                        "actualReceivers": [
                            f"{toid}@goofish",
                            f"{self.myid}@goofish"
                        ]
                    }
                ]
            }

            # 使用带重试机制的发送方法
            success = await self._send_image_msg_with_retry(ws, msg, toid, image_url)
            if not success:
                raise Exception("图片消息发送失败，已重试多次")

        except Exception as e:
            logger.error(f"【{self.cookie_id}】发送图片消息失败: {self._safe_str(e)}")
            raise

    async def send_image_from_file(self, ws, cid, toid, image_path):
        """从本地文件发送图片"""
        try:
            # 上传图片到闲鱼CDN
            logger.info(f"【{self.cookie_id}】开始上传图片: {image_path}")

            from utils.image_uploader import ImageUploader
            uploader = ImageUploader(self.cookies_str)

            async with uploader:
                image_url = await uploader.upload_image(image_path)

            if image_url:
                # 获取图片信息
                from utils.image_utils import image_manager
                try:
                    from PIL import Image
                    with Image.open(image_path) as img:
                        width, height = img.size
                except Exception as e:
                    logger.warning(f"无法获取图片尺寸，使用默认值: {e}")
                    width, height = 800, 600

                # 发送图片消息
                await self.send_image_msg(ws, cid, toid, image_url, width, height)
                logger.info(f"【{self.cookie_id}】图片发送完成: {image_path} -> {image_url}")
                return True
            else:
                logger.error(f"【{self.cookie_id}】图片上传失败: {image_path}")
                return False

        except Exception as e:
            logger.error(f"【{self.cookie_id}】从文件发送图片失败: {self._safe_str(e)}")
            return False

    def _get_single_coupon_content(self, rule: dict, order_id: str = None, item_id: str = None):
        """获取单个卡券内容，避免重复的商品信息保存等操作"""
        try:
            delivery_content = None
            
            # 根据卡券类型处理发货内容
            if rule['card_type'] == 'api':
                # API类型：JH API卡券已在主流程中处理，这里不应该被调用
                logger.warning("JH API类型卡券应在主流程中处理，不应调用_get_single_coupon_content")
                return None
                
            elif rule['card_type'] == 'text':
                # 固定文字类型：直接使用文字内容
                delivery_content = rule['text_content']
                
            elif rule['card_type'] == 'data':
                # 批量数据类型：先获取第一条数据但不消费，返回特殊标记
                # 实际消费将在发送成功后进行
                card_data = self._peek_batch_data(rule['card_id'])
                if card_data:
                    delivery_content = f"__BATCH_DATA__{rule['card_id']}|{card_data}"
                    
                    # 检查是否需要生成图片（不再限制为12位数字）
                    if delivery_content and delivery_content.startswith("__BATCH_DATA__"):
                        # 提取实际的卡密数据
                        parts = delivery_content.replace("__BATCH_DATA__", "").split("|", 1)
                        if len(parts) == 2:
                            card_id_str, actual_data = parts
                            # 检查是否需要生成图片
                            generate_image = rule.get('generate_image', True)  # 默认为True
                            logger.info(f"检测到卡密: {actual_data}，生成图片设置: {generate_image}")
                            
                            if generate_image:
                                logger.info(f"开始生成卡密图片: {actual_data}")
                                try:
                                    # 安全地处理actual_data，确保编码正确
                                    safe_actual_data = self._safe_encode_data(actual_data)
                                    logger.info(f"安全处理后的卡密数据: {safe_actual_data}")
                                    
                                    # 调用gm_main生成图片
                                    from GenerateCoupon import gm_main
                                    image_path = gm_main(safe_actual_data)
                                    
                                    if image_path and os.path.exists(image_path):
                                        # 移动图片到uploads目录
                                        import shutil
                                        upload_dir = "static/uploads"
                                        os.makedirs(upload_dir, exist_ok=True)
                                        
                                        # 生成新的文件名
                                        import uuid
                                        file_extension = os.path.splitext(image_path)[1]
                                        new_filename = f"coupon_{uuid.uuid4().hex[:8]}{file_extension}"
                                        new_image_path = os.path.join(upload_dir, new_filename)
                                        
                                        # 移动文件
                                        shutil.move(image_path, new_image_path)
                                        
                                        # 标准化路径格式（使用正斜杠）
                                        normalized_path = new_image_path.replace('\\', '/')
                                        
                                        # 检查是否有备注信息，决定使用哪种格式
                                        card_description = rule.get('card_description', '')
                                        if card_description and card_description.strip():
                                            # 有备注信息，使用新格式支持分离发送
                                            delivery_content = f"__BATCH_DATA_IMAGE_WITH_NOTE__{rule['card_id']}|{normalized_path}|{actual_data}|{card_description}"
                                            safe_path = self._safe_encode_data(normalized_path)
                                            logger.info(f"卡密图片生成成功(含备注): {safe_path}")
                                        else:
                                            # 无备注信息，使用原有格式
                                            delivery_content = f"__BATCH_DATA_IMAGE__{rule['card_id']}|{normalized_path}|{actual_data}"
                                            safe_path = self._safe_encode_data(normalized_path)
                                            logger.info(f"卡密图片生成成功: {safe_path}")
                                    else:
                                        safe_image_path = self._safe_encode_data(image_path) if image_path else "None"
                                        logger.error(f"图片生成失败或文件不存在: {safe_image_path}")
                                        # 如果图片生成失败，保持原始的批量数据标记
                                        logger.info(f"图片生成失败，保持原始批量数据标记")
                                except Exception as e:
                                    logger.error(f"生成卡密图片失败: {self._safe_str(e)}")
                                    # 如果出现异常，保持原始的批量数据标记
                                    logger.info(f"图片生成异常，保持原始批量数据标记")
                            else:
                                # 不生成图片，直接返回券码文本
                                logger.info(f"根据设置不生成图片，直接返回券码文本: {actual_data}")
                                # 保持原始的批量数据标记，但在后续处理中会作为文本发送
                else:
                    # 找到了规则但没有库存，返回特殊标记
                    logger.warning(f"找到发货规则但卡券无库存: 规则ID={rule['id']}, 卡券ID={rule['card_id']}")
                    return "__NO_STOCK__"
                    
            elif rule['card_type'] == 'image':
                # 图片类型：返回图片发送标记，包含卡券ID
                image_url = rule.get('image_url')
                if image_url:
                    delivery_content = f"__IMAGE_SEND__{rule['card_id']}|{image_url}"
                    logger.info(f"准备发送图片: {image_url} (卡券ID: {rule['card_id']})")
                else:
                    logger.error(f"图片卡券缺少图片URL: 卡券ID={rule['card_id']}")
                    delivery_content = None
            
            if delivery_content:
                # 对于特殊标记（如__BATCH_DATA_IMAGE_WITH_NOTE__），直接返回，不再进行备注处理
                # 因为备注信息已经包含在特殊标记中了
                if (delivery_content.startswith("__BATCH_DATA_IMAGE_WITH_NOTE__") or 
                    delivery_content.startswith("__BATCH_DATA_IMAGE__") or 
                    delivery_content.startswith("__BATCH_DATA__") or 
                    delivery_content.startswith("__IMAGE_SEND__")):
                    return delivery_content
                else:
                    # 处理备注信息和变量替换（仅对普通文本内容）
                    final_content = self._process_delivery_content_with_description(delivery_content, rule.get('card_description', ''))
                    return final_content
            else:
                logger.warning(f"获取发货内容失败: 规则ID={rule['id']}")
                return None
                
        except Exception as e:
            logger.error(f"获取单个卡券内容失败: {self._safe_str(e)}")
            return None

    def _peek_batch_data(self, card_id: int):
        """查看批量数据的第一条记录但不消费"""
        try:
            from db_manager import db_manager
            
            # 获取卡券的批量数据
            cursor = db_manager.conn.cursor()
            db_manager._execute_sql(cursor, "SELECT data_content FROM cards WHERE id = %s AND type = 'data'", (card_id,))
            result = cursor.fetchone()

            if not result or not result[0]:
                logger.warning(f"卡券 {card_id} 没有批量数据")
                return None

            data_content = result[0]
            lines = [line.strip() for line in data_content.split('\n') if line.strip()]

            if not lines:
                logger.warning(f"卡券 {card_id} 批量数据为空")
                return None

            # 返回第一条数据但不消费，确保编码安全
            first_data = lines[0]
            # 安全地处理编码
            safe_data = self._safe_encode_data(first_data)
            return safe_data

        except Exception as e:
            logger.error(f"查看批量数据失败: {self._safe_str(e)}")
            return None

    def _is_12_digit_code(self, text):
        """检查是否为12位数字，添加安全的编码处理"""
        try:
            if text is None:
                return False
            
            # 安全地处理编码
            safe_text = self._safe_encode_data(text)
            if not safe_text:
                return False
            
            # 使用正则表达式提取数字，更安全
            import re
            digits_only = re.sub(r'\D', '', safe_text)  # 移除所有非数字字符
            
            return len(digits_only) == 12
        except Exception as e:
            logger.warning(f"检查12位数字码时发生错误: {self._safe_str(e)}")
            return False

if __name__ == '__main__':
    cookies_str = os.getenv('COOKIES_STR')
    xianyuLive = XianyuLive(cookies_str)
    asyncio.run(xianyuLive.main())
